@classytic/stage 0.1.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/LICENSE +21 -0
- package/README.md +65 -0
- package/dist/assets/index.d.mts +3 -0
- package/dist/assets/index.mjs +5 -0
- package/dist/assets/kit/glyphs.d.mts +61 -0
- package/dist/assets/kit/glyphs.mjs +256 -0
- package/dist/assets/kit/index.d.mts +2 -0
- package/dist/assets/kit/index.mjs +4 -0
- package/dist/assets/kit/svg-defs.d.mts +6 -0
- package/dist/assets/kit/svg-defs.mjs +137 -0
- package/dist/builder/Palette.d.mts +30 -0
- package/dist/builder/Palette.mjs +100 -0
- package/dist/builder/SceneBuilder.d.mts +26 -0
- package/dist/builder/SceneBuilder.mjs +340 -0
- package/dist/builder/controls.d.mts +18 -0
- package/dist/builder/controls.mjs +29 -0
- package/dist/builder/editor.d.mts +46 -0
- package/dist/builder/editor.mjs +130 -0
- package/dist/builder/icons.d.mts +14 -0
- package/dist/builder/icons.mjs +143 -0
- package/dist/builder/index.d.mts +6 -0
- package/dist/builder/index.mjs +7 -0
- package/dist/builder/tools.d.mts +47 -0
- package/dist/builder/tools.mjs +303 -0
- package/dist/chem/index.d.mts +118 -0
- package/dist/chem/index.mjs +131 -0
- package/dist/core/clock.d.mts +41 -0
- package/dist/core/clock.mjs +62 -0
- package/dist/core/context.d.mts +13 -0
- package/dist/core/context.mjs +29 -0
- package/dist/core/control.d.mts +58 -0
- package/dist/core/control.mjs +113 -0
- package/dist/core/coords.d.mts +51 -0
- package/dist/core/coords.mjs +44 -0
- package/dist/core/index.d.mts +8 -0
- package/dist/core/index.mjs +9 -0
- package/dist/core/learner.d.mts +44 -0
- package/dist/core/learner.mjs +23 -0
- package/dist/core/motion.d.mts +73 -0
- package/dist/core/motion.mjs +103 -0
- package/dist/core/richText.d.mts +28 -0
- package/dist/core/richText.mjs +52 -0
- package/dist/core/vec.d.mts +47 -0
- package/dist/core/vec.mjs +144 -0
- package/dist/field/index.d.mts +58 -0
- package/dist/field/index.mjs +156 -0
- package/dist/index.d.mts +54 -0
- package/dist/index.mjs +55 -0
- package/dist/interaction/MovableDot.d.mts +33 -0
- package/dist/interaction/MovableDot.mjs +66 -0
- package/dist/interaction/hitTest.d.mts +16 -0
- package/dist/interaction/hitTest.mjs +39 -0
- package/dist/interaction/index.d.mts +5 -0
- package/dist/interaction/index.mjs +6 -0
- package/dist/interaction/useDraggable.d.mts +51 -0
- package/dist/interaction/useDraggable.mjs +116 -0
- package/dist/interaction/useScreenToMath.d.mts +12 -0
- package/dist/interaction/useScreenToMath.mjs +25 -0
- package/dist/logic/ast.d.mts +29 -0
- package/dist/logic/ast.mjs +37 -0
- package/dist/logic/index.d.mts +25 -0
- package/dist/logic/index.mjs +36 -0
- package/dist/logic/latex.d.mts +6 -0
- package/dist/logic/latex.mjs +33 -0
- package/dist/logic/minimize.d.mts +37 -0
- package/dist/logic/minimize.mjs +175 -0
- package/dist/logic/parse.d.mts +6 -0
- package/dist/logic/parse.mjs +68 -0
- package/dist/logic/table.d.mts +24 -0
- package/dist/logic/table.mjs +65 -0
- package/dist/logic/tokenize.mjs +258 -0
- package/dist/math/ast.d.mts +35 -0
- package/dist/math/ast.mjs +94 -0
- package/dist/math/calculus.d.mts +9 -0
- package/dist/math/calculus.mjs +188 -0
- package/dist/math/defs.mjs +51 -0
- package/dist/math/index.d.mts +26 -0
- package/dist/math/index.mjs +42 -0
- package/dist/math/latex.d.mts +7 -0
- package/dist/math/latex.mjs +115 -0
- package/dist/math/parse.d.mts +6 -0
- package/dist/math/parse.mjs +91 -0
- package/dist/math/tokenize.mjs +112 -0
- package/dist/primitives/CanvasLayer.d.mts +26 -0
- package/dist/primitives/CanvasLayer.mjs +87 -0
- package/dist/primitives/Dot.d.mts +27 -0
- package/dist/primitives/Dot.mjs +40 -0
- package/dist/primitives/Grid.d.mts +30 -0
- package/dist/primitives/Grid.mjs +122 -0
- package/dist/primitives/Label.d.mts +33 -0
- package/dist/primitives/Label.mjs +45 -0
- package/dist/primitives/Lines.d.mts +50 -0
- package/dist/primitives/Lines.mjs +82 -0
- package/dist/primitives/Plot.d.mts +50 -0
- package/dist/primitives/Plot.mjs +87 -0
- package/dist/primitives/Shapes.d.mts +76 -0
- package/dist/primitives/Shapes.mjs +79 -0
- package/dist/primitives/Tex.d.mts +27 -0
- package/dist/primitives/Tex.mjs +54 -0
- package/dist/primitives/index.d.mts +10 -0
- package/dist/primitives/index.mjs +10 -0
- package/dist/primitives/props.d.mts +15 -0
- package/dist/scene/Scene.d.mts +31 -0
- package/dist/scene/Scene.mjs +168 -0
- package/dist/scene/assets.d.mts +37 -0
- package/dist/scene/assets.mjs +31 -0
- package/dist/scene/commands.d.mts +47 -0
- package/dist/scene/commands.mjs +162 -0
- package/dist/scene/evaluators.d.mts +17 -0
- package/dist/scene/evaluators.mjs +210 -0
- package/dist/scene/index.d.mts +13 -0
- package/dist/scene/index.mjs +13 -0
- package/dist/scene/migrate.d.mts +11 -0
- package/dist/scene/migrate.mjs +35 -0
- package/dist/scene/render.d.mts +14 -0
- package/dist/scene/render.mjs +126 -0
- package/dist/scene/resolve.d.mts +12 -0
- package/dist/scene/resolve.mjs +95 -0
- package/dist/scene/schema.d.mts +9 -0
- package/dist/scene/schema.mjs +51 -0
- package/dist/scene/sims.d.mts +18 -0
- package/dist/scene/sims.mjs +54 -0
- package/dist/scene/store.d.mts +22 -0
- package/dist/scene/store.mjs +37 -0
- package/dist/scene/types.d.mts +228 -0
- package/dist/scene/types.mjs +27 -0
- package/dist/sim/equilibrium.d.mts +36 -0
- package/dist/sim/equilibrium.mjs +54 -0
- package/dist/sim/index.d.mts +9 -0
- package/dist/sim/index.mjs +9 -0
- package/dist/sim/particles.d.mts +43 -0
- package/dist/sim/particles.mjs +136 -0
- package/dist/sim/rate.d.mts +36 -0
- package/dist/sim/rate.mjs +39 -0
- package/dist/sim/registry.d.mts +10 -0
- package/dist/sim/registry.mjs +27 -0
- package/dist/sim/sampler.d.mts +47 -0
- package/dist/sim/sampler.mjs +79 -0
- package/dist/sim/thermal.d.mts +78 -0
- package/dist/sim/thermal.mjs +172 -0
- package/dist/sim/types.d.mts +24 -0
- package/dist/sim/wave.d.mts +34 -0
- package/dist/sim/wave.mjs +61 -0
- package/dist/steps/index.d.mts +62 -0
- package/dist/steps/index.mjs +133 -0
- package/dist/thermo/index.d.mts +82 -0
- package/dist/thermo/index.mjs +133 -0
- package/dist/view/Stage.d.mts +39 -0
- package/dist/view/Stage.mjs +91 -0
- package/dist/view/index.d.mts +4 -0
- package/dist/view/index.mjs +5 -0
- package/dist/view/useElementSize.d.mts +13 -0
- package/dist/view/useElementSize.mjs +40 -0
- package/dist/view/useInView.d.mts +9 -0
- package/dist/view/useInView.mjs +33 -0
- package/package.json +141 -0
- package/styles.css +70 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Binding, DerivedDef, ElementStyle, Id, SceneDoc, SceneElement } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/scene/commands.d.ts
|
|
4
|
+
interface MutatePatch {
|
|
5
|
+
free?: Record<string, unknown>;
|
|
6
|
+
def?: Partial<DerivedDef>;
|
|
7
|
+
style?: ElementStyle;
|
|
8
|
+
label?: string;
|
|
9
|
+
}
|
|
10
|
+
type Command = {
|
|
11
|
+
op: 'create';
|
|
12
|
+
id: Id;
|
|
13
|
+
element: SceneElement;
|
|
14
|
+
index?: number;
|
|
15
|
+
} | {
|
|
16
|
+
op: 'mutate';
|
|
17
|
+
id: Id;
|
|
18
|
+
patch: MutatePatch;
|
|
19
|
+
} | {
|
|
20
|
+
op: 'bind';
|
|
21
|
+
binding: Binding;
|
|
22
|
+
} | {
|
|
23
|
+
op: 'unbind';
|
|
24
|
+
id: Id;
|
|
25
|
+
} | {
|
|
26
|
+
op: 'remove';
|
|
27
|
+
id: Id;
|
|
28
|
+
} | {
|
|
29
|
+
op: 'batch';
|
|
30
|
+
label: string;
|
|
31
|
+
commands: Command[];
|
|
32
|
+
};
|
|
33
|
+
interface CommandResult {
|
|
34
|
+
ok: boolean;
|
|
35
|
+
createdIds?: Id[];
|
|
36
|
+
error?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Elements transitively depending on `id` (plus `id` itself), in document order
|
|
39
|
+
* (= creation order, parents before children), and the bindings touching them. */
|
|
40
|
+
declare function collectRemoved(doc: SceneDoc, id: Id): {
|
|
41
|
+
elements: SceneElement[];
|
|
42
|
+
bindings: Binding[];
|
|
43
|
+
};
|
|
44
|
+
declare function applyCommand(doc: SceneDoc, cmd: Command): SceneDoc;
|
|
45
|
+
declare function inverse(cmd: Command, prev: SceneDoc): Command;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { Command, CommandResult, MutatePatch, applyCommand, collectRemoved, inverse };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { isDerived, isFree } from "./types.mjs";
|
|
2
|
+
import { parentIds } from "./schema.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/scene/commands.ts
|
|
5
|
+
/**
|
|
6
|
+
* Commands — JSON, agent-emittable mutations. ALL changes funnel through these
|
|
7
|
+
* (builder, agent, undo, control-surface bridge). GeoGebra create-vs-mutate split.
|
|
8
|
+
* `applyCommand` is a pure reducer; `inverse` produces the undo command, including
|
|
9
|
+
* a concrete cascading-remove inverse that re-creates descendants + bindings in
|
|
10
|
+
* dependency order.
|
|
11
|
+
*/
|
|
12
|
+
function mutateElement(el, patch) {
|
|
13
|
+
const next = { ...el };
|
|
14
|
+
if (patch.label !== void 0) next.label = patch.label;
|
|
15
|
+
if (patch.style) next.style = {
|
|
16
|
+
...el.style,
|
|
17
|
+
...patch.style
|
|
18
|
+
};
|
|
19
|
+
if (patch.free && isFree(next) && isFree(el)) next.free = {
|
|
20
|
+
...el.free,
|
|
21
|
+
...patch.free
|
|
22
|
+
};
|
|
23
|
+
if (patch.def && isDerived(next) && isDerived(el)) next.def = {
|
|
24
|
+
...el.def,
|
|
25
|
+
...patch.def
|
|
26
|
+
};
|
|
27
|
+
return next;
|
|
28
|
+
}
|
|
29
|
+
/** Elements transitively depending on `id` (plus `id` itself), in document order
|
|
30
|
+
* (= creation order, parents before children), and the bindings touching them. */
|
|
31
|
+
function collectRemoved(doc, id) {
|
|
32
|
+
const removed = new Set([id]);
|
|
33
|
+
let changed = true;
|
|
34
|
+
while (changed) {
|
|
35
|
+
changed = false;
|
|
36
|
+
for (const el of doc.elements) {
|
|
37
|
+
if (removed.has(el.id)) continue;
|
|
38
|
+
const ps = parentIds(el);
|
|
39
|
+
const boundTo = doc.bindings.filter((b) => b.from.ref === el.id).map((b) => b.to.ref);
|
|
40
|
+
if ([...ps, ...boundTo].some((p) => removed.has(p))) {
|
|
41
|
+
removed.add(el.id);
|
|
42
|
+
changed = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
elements: doc.elements.filter((e) => removed.has(e.id)),
|
|
48
|
+
bindings: doc.bindings.filter((b) => removed.has(b.from.ref) || removed.has(b.to.ref))
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function applyCommand(doc, cmd) {
|
|
52
|
+
switch (cmd.op) {
|
|
53
|
+
case "create": {
|
|
54
|
+
if (cmd.index == null) return {
|
|
55
|
+
...doc,
|
|
56
|
+
elements: [...doc.elements, cmd.element]
|
|
57
|
+
};
|
|
58
|
+
const els = doc.elements.slice();
|
|
59
|
+
els.splice(cmd.index, 0, cmd.element);
|
|
60
|
+
return {
|
|
61
|
+
...doc,
|
|
62
|
+
elements: els
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
case "mutate": return {
|
|
66
|
+
...doc,
|
|
67
|
+
elements: doc.elements.map((el) => el.id === cmd.id ? mutateElement(el, cmd.patch) : el)
|
|
68
|
+
};
|
|
69
|
+
case "bind": return {
|
|
70
|
+
...doc,
|
|
71
|
+
bindings: [...doc.bindings, cmd.binding]
|
|
72
|
+
};
|
|
73
|
+
case "unbind": return {
|
|
74
|
+
...doc,
|
|
75
|
+
bindings: doc.bindings.filter((b) => b.id !== cmd.id)
|
|
76
|
+
};
|
|
77
|
+
case "remove": {
|
|
78
|
+
const { elements, bindings } = collectRemoved(doc, cmd.id);
|
|
79
|
+
const elIds = new Set(elements.map((e) => e.id));
|
|
80
|
+
const bIds = new Set(bindings.map((b) => b.id));
|
|
81
|
+
return {
|
|
82
|
+
...doc,
|
|
83
|
+
elements: doc.elements.filter((e) => !elIds.has(e.id)),
|
|
84
|
+
bindings: doc.bindings.filter((b) => !bIds.has(b.id))
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
case "batch": return cmd.commands.reduce(applyCommand, doc);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function inverse(cmd, prev) {
|
|
91
|
+
switch (cmd.op) {
|
|
92
|
+
case "create": return {
|
|
93
|
+
op: "remove",
|
|
94
|
+
id: cmd.id
|
|
95
|
+
};
|
|
96
|
+
case "mutate": {
|
|
97
|
+
const el = prev.elements.find((e) => e.id === cmd.id);
|
|
98
|
+
const patch = {};
|
|
99
|
+
if (el) {
|
|
100
|
+
if (cmd.patch.label !== void 0) patch.label = el.label ?? "";
|
|
101
|
+
if (cmd.patch.style) patch.style = el.style ?? {};
|
|
102
|
+
if (cmd.patch.free && isFree(el)) patch.free = { ...el.free };
|
|
103
|
+
if (cmd.patch.def && isDerived(el)) patch.def = { ...el.def };
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
op: "mutate",
|
|
107
|
+
id: cmd.id,
|
|
108
|
+
patch
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
case "bind": return {
|
|
112
|
+
op: "unbind",
|
|
113
|
+
id: cmd.binding.id
|
|
114
|
+
};
|
|
115
|
+
case "unbind": {
|
|
116
|
+
const b = prev.bindings.find((x) => x.id === cmd.id);
|
|
117
|
+
if (!b) return {
|
|
118
|
+
op: "batch",
|
|
119
|
+
label: "noop",
|
|
120
|
+
commands: []
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
op: "bind",
|
|
124
|
+
binding: b
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
case "remove": {
|
|
128
|
+
const { elements, bindings } = collectRemoved(prev, cmd.id);
|
|
129
|
+
return {
|
|
130
|
+
op: "batch",
|
|
131
|
+
label: "undo remove",
|
|
132
|
+
commands: [...elements.map((element) => ({
|
|
133
|
+
op: "create",
|
|
134
|
+
id: element.id,
|
|
135
|
+
element,
|
|
136
|
+
index: prev.elements.indexOf(element)
|
|
137
|
+
})), ...bindings.map((binding) => ({
|
|
138
|
+
op: "bind",
|
|
139
|
+
binding
|
|
140
|
+
}))]
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
case "batch": {
|
|
144
|
+
const inverses = [];
|
|
145
|
+
let cursor = prev;
|
|
146
|
+
const states = [];
|
|
147
|
+
for (const c of cmd.commands) {
|
|
148
|
+
states.push(cursor);
|
|
149
|
+
cursor = applyCommand(cursor, c);
|
|
150
|
+
}
|
|
151
|
+
for (let i = cmd.commands.length - 1; i >= 0; i--) inverses.push(inverse(cmd.commands[i], states[i]));
|
|
152
|
+
return {
|
|
153
|
+
op: "batch",
|
|
154
|
+
label: `undo ${cmd.label}`,
|
|
155
|
+
commands: inverses
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//#endregion
|
|
162
|
+
export { applyCommand, collectRemoved, inverse };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Vec2 } from "../core/vec.mjs";
|
|
2
|
+
import { DerivedDef, Id, NumOrRef, Ref, Val } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/scene/evaluators.d.ts
|
|
5
|
+
interface EvalCtx {
|
|
6
|
+
get(r: Ref): Val | undefined;
|
|
7
|
+
vec(r: Ref): Vec2 | undefined;
|
|
8
|
+
num(x: NumOrRef): number;
|
|
9
|
+
prevVal(id: Id): Val | undefined;
|
|
10
|
+
/** Read a live sim-state field (external input, like a drag overlay). */
|
|
11
|
+
simField(sim: Id, field: string): unknown;
|
|
12
|
+
selfId: Id;
|
|
13
|
+
}
|
|
14
|
+
type Evaluator = (def: DerivedDef, ctx: EvalCtx) => Val;
|
|
15
|
+
declare const EVALUATORS: Record<string, Evaluator>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { EVALUATORS, EvalCtx };
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { vec } from "../core/vec.mjs";
|
|
2
|
+
import { isCircleVal, isLineVal, isVec2, numOf } from "./types.mjs";
|
|
3
|
+
import { getAsset } from "./assets.mjs";
|
|
4
|
+
import { compileExpr } from "../math/index.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/scene/evaluators.ts
|
|
7
|
+
/**
|
|
8
|
+
* Evaluator registry, keyed by def.op. Each evaluator turns a derived def into a
|
|
9
|
+
* Val, reading parent values through `ctx`. Geometry intersection math is ported
|
|
10
|
+
* from the legacy labs GeometryBoard; intersect picks the solution nearest the previous
|
|
11
|
+
* frame's resolved point (continuity — never swaps P/Q on drag).
|
|
12
|
+
*/
|
|
13
|
+
const exprCache = /* @__PURE__ */ new Map();
|
|
14
|
+
function compiledExpr(src) {
|
|
15
|
+
if (exprCache.has(src)) return exprCache.get(src) ?? null;
|
|
16
|
+
const r = compileExpr(src);
|
|
17
|
+
const compiled = "fn" in r && typeof r.fn === "function" ? r : null;
|
|
18
|
+
exprCache.set(src, compiled);
|
|
19
|
+
return compiled;
|
|
20
|
+
}
|
|
21
|
+
const dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
22
|
+
function intersectCircleCircle(A, B) {
|
|
23
|
+
const d = dist(A.center, B.center);
|
|
24
|
+
if (d < 1e-9 || d > A.r + B.r || d < Math.abs(A.r - B.r)) return [];
|
|
25
|
+
const a = (d * d + A.r * A.r - B.r * B.r) / (2 * d);
|
|
26
|
+
const h2 = A.r * A.r - a * a;
|
|
27
|
+
if (h2 < 0) return [];
|
|
28
|
+
const h = Math.sqrt(h2);
|
|
29
|
+
const ux = (B.center.x - A.center.x) / d;
|
|
30
|
+
const uy = (B.center.y - A.center.y) / d;
|
|
31
|
+
const mx = A.center.x + a * ux;
|
|
32
|
+
const my = A.center.y + a * uy;
|
|
33
|
+
return [{
|
|
34
|
+
x: mx - h * uy,
|
|
35
|
+
y: my + h * ux
|
|
36
|
+
}, {
|
|
37
|
+
x: mx + h * uy,
|
|
38
|
+
y: my - h * ux
|
|
39
|
+
}];
|
|
40
|
+
}
|
|
41
|
+
function intersectLineLine(L1, L2) {
|
|
42
|
+
const { a: p1, b: p2 } = L1;
|
|
43
|
+
const { a: p3, b: p4 } = L2;
|
|
44
|
+
const d = (p1.x - p2.x) * (p3.y - p4.y) - (p1.y - p2.y) * (p3.x - p4.x);
|
|
45
|
+
if (Math.abs(d) < 1e-9) return [];
|
|
46
|
+
const a = p1.x * p2.y - p1.y * p2.x;
|
|
47
|
+
const b = p3.x * p4.y - p3.y * p4.x;
|
|
48
|
+
return [{
|
|
49
|
+
x: (a * (p3.x - p4.x) - (p1.x - p2.x) * b) / d,
|
|
50
|
+
y: (a * (p3.y - p4.y) - (p1.y - p2.y) * b) / d
|
|
51
|
+
}];
|
|
52
|
+
}
|
|
53
|
+
function intersectLineCircle(L, C) {
|
|
54
|
+
const dx = L.b.x - L.a.x;
|
|
55
|
+
const dy = L.b.y - L.a.y;
|
|
56
|
+
const fx = L.a.x - C.center.x;
|
|
57
|
+
const fy = L.a.y - C.center.y;
|
|
58
|
+
const a = dx * dx + dy * dy;
|
|
59
|
+
const b = 2 * (fx * dx + fy * dy);
|
|
60
|
+
const c = fx * fx + fy * fy - C.r * C.r;
|
|
61
|
+
const disc = b * b - 4 * a * c;
|
|
62
|
+
if (disc < 0 || a < 1e-12) return [];
|
|
63
|
+
const s = Math.sqrt(disc);
|
|
64
|
+
const t1 = (-b - s) / (2 * a);
|
|
65
|
+
const t2 = (-b + s) / (2 * a);
|
|
66
|
+
return [{
|
|
67
|
+
x: L.a.x + t1 * dx,
|
|
68
|
+
y: L.a.y + t1 * dy
|
|
69
|
+
}, {
|
|
70
|
+
x: L.a.x + t2 * dx,
|
|
71
|
+
y: L.a.y + t2 * dy
|
|
72
|
+
}];
|
|
73
|
+
}
|
|
74
|
+
function need(v, msg) {
|
|
75
|
+
if (v === void 0) throw new Error(msg);
|
|
76
|
+
return v;
|
|
77
|
+
}
|
|
78
|
+
const EVALUATORS = {
|
|
79
|
+
midpoint: (d, ctx) => {
|
|
80
|
+
const def = d;
|
|
81
|
+
return vec.midpoint(need(ctx.vec(def.of[0]), "midpoint: parent A missing"), need(ctx.vec(def.of[1]), "midpoint: parent B missing"));
|
|
82
|
+
},
|
|
83
|
+
circle: (d, ctx) => {
|
|
84
|
+
const def = d;
|
|
85
|
+
const center = need(ctx.vec(def.center), "circle: center missing");
|
|
86
|
+
return {
|
|
87
|
+
kind: "circle",
|
|
88
|
+
center,
|
|
89
|
+
r: def.radius != null ? def.radius : def.through ? dist(center, need(ctx.vec(def.through), "circle: through missing")) : 1
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
line: (d, ctx) => {
|
|
93
|
+
const def = d;
|
|
94
|
+
return {
|
|
95
|
+
kind: "line",
|
|
96
|
+
a: need(ctx.vec(def.through[0]), "line: A missing"),
|
|
97
|
+
b: need(ctx.vec(def.through[1]), "line: B missing")
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
segment: (d, ctx) => {
|
|
101
|
+
const def = d;
|
|
102
|
+
return {
|
|
103
|
+
kind: "segment",
|
|
104
|
+
a: need(ctx.vec(def.from), "segment: from missing"),
|
|
105
|
+
b: need(ctx.vec(def.to), "segment: to missing")
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
polygon: (d, ctx) => {
|
|
109
|
+
return d.vertices.map((r, i) => need(ctx.vec(r), `polygon: vertex ${i} missing`));
|
|
110
|
+
},
|
|
111
|
+
intersect: (d, ctx) => {
|
|
112
|
+
const def = d;
|
|
113
|
+
const v1 = ctx.get(def.of[0]);
|
|
114
|
+
const v2 = ctx.get(def.of[1]);
|
|
115
|
+
let sols = [];
|
|
116
|
+
if (isCircleVal(v1) && isCircleVal(v2)) sols = intersectCircleCircle(v1, v2);
|
|
117
|
+
else if (isLineVal(v1) && isLineVal(v2)) sols = intersectLineLine(v1, v2);
|
|
118
|
+
else if (isLineVal(v1) && isCircleVal(v2)) sols = intersectLineCircle(v1, v2);
|
|
119
|
+
else if (isCircleVal(v1) && isLineVal(v2)) sols = intersectLineCircle(v2, v1);
|
|
120
|
+
if (!sols.length) throw new Error("intersect: no solution");
|
|
121
|
+
const prev = ctx.prevVal(ctx.selfId);
|
|
122
|
+
if (isVec2(prev)) return sols.reduce((best, s) => dist(s, prev) < dist(best, prev) ? s : best, sols[0]);
|
|
123
|
+
return sols[def.pick ?? 0] ?? sols[0];
|
|
124
|
+
},
|
|
125
|
+
distance: (d, ctx) => {
|
|
126
|
+
const def = d;
|
|
127
|
+
return dist(need(ctx.vec(def.of[0]), "distance: A missing"), need(ctx.vec(def.of[1]), "distance: B missing"));
|
|
128
|
+
},
|
|
129
|
+
angle: (d, ctx) => {
|
|
130
|
+
const def = d;
|
|
131
|
+
const a = need(ctx.vec(def.of[0]), "angle: A");
|
|
132
|
+
const o = need(ctx.vec(def.of[1]), "angle: vertex");
|
|
133
|
+
const b = need(ctx.vec(def.of[2]), "angle: C");
|
|
134
|
+
const u = vec.sub(a, o);
|
|
135
|
+
const w = vec.sub(b, o);
|
|
136
|
+
const cos = vec.dot(u, w) / ((vec.mag(u) || 1) * (vec.mag(w) || 1));
|
|
137
|
+
return Math.acos(Math.max(-1, Math.min(1, cos))) * (180 / Math.PI);
|
|
138
|
+
},
|
|
139
|
+
linop: (d, ctx) => {
|
|
140
|
+
const def = d;
|
|
141
|
+
return def.terms.reduce((sum, t) => sum + t.coef * numOf(ctx.get(t.in)), def.const ?? 0);
|
|
142
|
+
},
|
|
143
|
+
clamp: (d, ctx) => {
|
|
144
|
+
const def = d;
|
|
145
|
+
return Math.max(def.min, Math.min(def.max, numOf(ctx.get(def.in))));
|
|
146
|
+
},
|
|
147
|
+
lerp: (d, ctx) => {
|
|
148
|
+
const def = d;
|
|
149
|
+
const a = numOf(ctx.get(def.a));
|
|
150
|
+
return a + (numOf(ctx.get(def.b)) - a) * ctx.num(def.t);
|
|
151
|
+
},
|
|
152
|
+
reduce: (d, ctx) => {
|
|
153
|
+
const def = d;
|
|
154
|
+
const xs = def.inputs.map((r) => numOf(ctx.get(r)));
|
|
155
|
+
if (!xs.length) return 0;
|
|
156
|
+
if (def.reducer === "sum") return xs.reduce((a, b) => a + b, 0);
|
|
157
|
+
if (def.reducer === "mean") return xs.reduce((a, b) => a + b, 0) / xs.length;
|
|
158
|
+
if (def.reducer === "max") return Math.max(...xs);
|
|
159
|
+
return Math.min(...xs);
|
|
160
|
+
},
|
|
161
|
+
product: (d, ctx) => {
|
|
162
|
+
const def = d;
|
|
163
|
+
return numOf(ctx.get(def.of[0])) * numOf(ctx.get(def.of[1]));
|
|
164
|
+
},
|
|
165
|
+
compare: (d, ctx) => {
|
|
166
|
+
const def = d;
|
|
167
|
+
const a = numOf(ctx.get(def.a));
|
|
168
|
+
const b = ctx.num(def.b);
|
|
169
|
+
const eps = def.eps ?? 0;
|
|
170
|
+
switch (def.cmp) {
|
|
171
|
+
case "lt": return a < b - eps;
|
|
172
|
+
case "le": return a <= b + eps;
|
|
173
|
+
case "eq": return Math.abs(a - b) <= eps;
|
|
174
|
+
case "ge": return a >= b - eps;
|
|
175
|
+
case "gt": return a > b + eps;
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
select: (d, ctx) => {
|
|
179
|
+
const def = d;
|
|
180
|
+
return numOf(ctx.get(def.cond)) !== 0 ? ctx.num(def.then) : ctx.num(def.else);
|
|
181
|
+
},
|
|
182
|
+
expr: (d, ctx) => {
|
|
183
|
+
const def = d;
|
|
184
|
+
const compiled = compiledExpr(def.fn);
|
|
185
|
+
if (!compiled) return NaN;
|
|
186
|
+
const scope = {};
|
|
187
|
+
for (const [name, ref] of Object.entries(def.inputs)) scope[name] = numOf(ctx.get(ref));
|
|
188
|
+
return compiled.fn(scope);
|
|
189
|
+
},
|
|
190
|
+
asset: (d, ctx) => {
|
|
191
|
+
const def = d;
|
|
192
|
+
const spec = getAsset(def.asset);
|
|
193
|
+
if (!spec) throw new Error(`asset '${def.asset}' not registered`);
|
|
194
|
+
const bound = {};
|
|
195
|
+
for (const [k, ref] of Object.entries(def.bind)) bound[k] = ctx.get(ref);
|
|
196
|
+
let sim;
|
|
197
|
+
if (def.simBind) {
|
|
198
|
+
sim = {};
|
|
199
|
+
for (const [k, b] of Object.entries(def.simBind)) sim[k] = ctx.simField(b.sim, b.field);
|
|
200
|
+
}
|
|
201
|
+
return spec.resolver({
|
|
202
|
+
params: def.params,
|
|
203
|
+
bound,
|
|
204
|
+
sim
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
export { EVALUATORS };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Vec2 } from "../core/vec.mjs";
|
|
2
|
+
import { AssetGeometry, Binding, CircleVal, DerivedDef, DerivedElement, DerivedKind, ElementBase, ElementStyle, FreeElement, FreeNote, FreePoint, FreeScalar, Id, LabMeta, NumOrRef, Op, Ref, SceneDoc, SceneElement, SceneMeta, ShapeLineVal, SimDecl, Val, isAssetGeom, isCircleVal, isDerived, isFree, isLineVal, isVec2, numOf } from "./types.mjs";
|
|
3
|
+
import { Command, CommandResult, MutatePatch, applyCommand, collectRemoved, inverse } from "./commands.mjs";
|
|
4
|
+
import { Resolved, resolve } from "./resolve.mjs";
|
|
5
|
+
import { OP_REFS, isRef, parentIds } from "./schema.mjs";
|
|
6
|
+
import { EVALUATORS, EvalCtx } from "./evaluators.mjs";
|
|
7
|
+
import { CURRENT_SCHEMA_VERSION, emptyDoc, migrate, parse, serialize } from "./migrate.mjs";
|
|
8
|
+
import { InstanceState, SceneStore } from "./store.mjs";
|
|
9
|
+
import { Scene, SceneProps } from "./Scene.mjs";
|
|
10
|
+
import { RenderOpts, renderElements } from "./render.mjs";
|
|
11
|
+
import { AssetResolveArgs, AssetSpec, assetMeta, getAsset, listAssets, registerAsset } from "./assets.mjs";
|
|
12
|
+
import { SimStates, initSims, stepSims } from "./sims.mjs";
|
|
13
|
+
export { type AssetGeometry, type AssetResolveArgs, type AssetSpec, type Binding, CURRENT_SCHEMA_VERSION, type CircleVal, type Command, type CommandResult, type DerivedDef, type DerivedElement, type DerivedKind, EVALUATORS, type ElementBase, type ElementStyle, type EvalCtx, type FreeElement, type FreeNote, type FreePoint, type FreeScalar, type Id, type InstanceState, type LabMeta, type MutatePatch, type NumOrRef, OP_REFS, type Op, type Ref, type RenderOpts, type Resolved, Scene, type SceneDoc, type SceneElement, type SceneMeta, type SceneProps, SceneStore, type Vec2 as SceneVec2, type ShapeLineVal, type SimDecl, type SimStates, type Val, applyCommand, assetMeta, collectRemoved, emptyDoc, getAsset, initSims, inverse, isAssetGeom, isCircleVal, isDerived, isFree, isLineVal, isRef, isVec2, listAssets, migrate, numOf, parentIds, parse, registerAsset, renderElements, resolve, serialize, stepSims };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isAssetGeom, isCircleVal, isDerived, isFree, isLineVal, isVec2, numOf } from "./types.mjs";
|
|
2
|
+
import { OP_REFS, isRef, parentIds } from "./schema.mjs";
|
|
3
|
+
import { assetMeta, getAsset, listAssets, registerAsset } from "./assets.mjs";
|
|
4
|
+
import { EVALUATORS } from "./evaluators.mjs";
|
|
5
|
+
import { resolve } from "./resolve.mjs";
|
|
6
|
+
import { applyCommand, collectRemoved, inverse } from "./commands.mjs";
|
|
7
|
+
import { CURRENT_SCHEMA_VERSION, emptyDoc, migrate, parse, serialize } from "./migrate.mjs";
|
|
8
|
+
import { SceneStore } from "./store.mjs";
|
|
9
|
+
import { renderElements } from "./render.mjs";
|
|
10
|
+
import { initSims, stepSims } from "./sims.mjs";
|
|
11
|
+
import { Scene } from "./Scene.mjs";
|
|
12
|
+
|
|
13
|
+
export { CURRENT_SCHEMA_VERSION, EVALUATORS, OP_REFS, Scene, SceneStore, applyCommand, assetMeta, collectRemoved, emptyDoc, getAsset, initSims, inverse, isAssetGeom, isCircleVal, isDerived, isFree, isLineVal, isRef, isVec2, listAssets, migrate, numOf, parentIds, parse, registerAsset, renderElements, resolve, serialize, stepSims };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SceneDoc } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/scene/migrate.d.ts
|
|
4
|
+
declare const CURRENT_SCHEMA_VERSION: 2;
|
|
5
|
+
declare function emptyDoc(): SceneDoc;
|
|
6
|
+
declare function migrate(raw: unknown): SceneDoc;
|
|
7
|
+
/** Stable JSON serialize (sorted nowhere needed yet; element order is meaningful). */
|
|
8
|
+
declare function serialize(doc: SceneDoc): string;
|
|
9
|
+
declare function parse(json: string): SceneDoc;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { CURRENT_SCHEMA_VERSION, emptyDoc, migrate, parse, serialize };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/scene/migrate.ts
|
|
2
|
+
const CURRENT_SCHEMA_VERSION = 2;
|
|
3
|
+
function emptyDoc() {
|
|
4
|
+
return {
|
|
5
|
+
schemaVersion: 2,
|
|
6
|
+
type: "stage-scene",
|
|
7
|
+
elements: [],
|
|
8
|
+
bindings: []
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function migrate(raw) {
|
|
12
|
+
if (Array.isArray(raw)) throw new Error("legacy GeoElement[] array — use the geoToScene codec (Phase 6)");
|
|
13
|
+
if (!raw || typeof raw !== "object") return emptyDoc();
|
|
14
|
+
const doc = raw;
|
|
15
|
+
return {
|
|
16
|
+
schemaVersion: 2,
|
|
17
|
+
type: "stage-scene",
|
|
18
|
+
view: doc.view,
|
|
19
|
+
width: doc.width,
|
|
20
|
+
height: doc.height,
|
|
21
|
+
elements: doc.elements ?? [],
|
|
22
|
+
bindings: doc.bindings ?? [],
|
|
23
|
+
meta: doc.meta
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Stable JSON serialize (sorted nowhere needed yet; element order is meaningful). */
|
|
27
|
+
function serialize(doc) {
|
|
28
|
+
return JSON.stringify(doc);
|
|
29
|
+
}
|
|
30
|
+
function parse(json) {
|
|
31
|
+
return migrate(JSON.parse(json));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { CURRENT_SCHEMA_VERSION, emptyDoc, migrate, parse, serialize };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Vec2 } from "../core/vec.mjs";
|
|
2
|
+
import { Id, SceneDoc } from "./types.mjs";
|
|
3
|
+
import { Resolved } from "./resolve.mjs";
|
|
4
|
+
import { ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
//#region src/scene/render.d.ts
|
|
7
|
+
interface RenderOpts {
|
|
8
|
+
draggablePoints: boolean;
|
|
9
|
+
onPointMove?: (id: Id, p: Vec2, phase: 'move' | 'commit') => void;
|
|
10
|
+
selection?: Id | null;
|
|
11
|
+
}
|
|
12
|
+
declare function renderElements(doc: SceneDoc, resolved: Resolved, opts: RenderOpts): ReactNode;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { RenderOpts, renderElements };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { vec } from "../core/vec.mjs";
|
|
4
|
+
import { Point } from "../primitives/Dot.mjs";
|
|
5
|
+
import { Line, Segment } from "../primitives/Lines.mjs";
|
|
6
|
+
import { Circle, Polygon } from "../primitives/Shapes.mjs";
|
|
7
|
+
import { Label } from "../primitives/Label.mjs";
|
|
8
|
+
import { MovableDot } from "../interaction/MovableDot.mjs";
|
|
9
|
+
import { isAssetGeom, isCircleVal, isDerived, isLineVal, isVec2 } from "./types.mjs";
|
|
10
|
+
import { getAsset } from "./assets.mjs";
|
|
11
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
|
|
13
|
+
//#region src/scene/render.tsx
|
|
14
|
+
function parentRef(el, i) {
|
|
15
|
+
if (!isDerived(el)) return "";
|
|
16
|
+
const def = el.def;
|
|
17
|
+
if (def.op === "distance" || def.op === "angle") return def.of[i]?.ref ?? "";
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
function renderElements(doc, resolved, opts) {
|
|
21
|
+
const shapes = [];
|
|
22
|
+
const overlays = [];
|
|
23
|
+
const point = (ref) => {
|
|
24
|
+
const v = resolved.values.get(ref);
|
|
25
|
+
return isVec2(v) ? v : void 0;
|
|
26
|
+
};
|
|
27
|
+
for (const el of doc.elements) {
|
|
28
|
+
if (el.style?.hidden) continue;
|
|
29
|
+
const val = resolved.values.get(el.id);
|
|
30
|
+
const color = el.style?.color;
|
|
31
|
+
if (el.kind === "asset" && isAssetGeom(val) && isDerived(el) && el.def.op === "asset") {
|
|
32
|
+
const spec = getAsset(el.def.asset);
|
|
33
|
+
if (spec) {
|
|
34
|
+
const C = spec.Component;
|
|
35
|
+
shapes.push(/* @__PURE__ */ jsx(C, {
|
|
36
|
+
geom: val,
|
|
37
|
+
style: el.style,
|
|
38
|
+
label: el.label
|
|
39
|
+
}, el.id));
|
|
40
|
+
}
|
|
41
|
+
} else if (el.kind === "circle" && isCircleVal(val)) shapes.push(/* @__PURE__ */ jsx(Circle, {
|
|
42
|
+
center: val.center,
|
|
43
|
+
r: val.r,
|
|
44
|
+
color: color ?? "var(--stage-accent)",
|
|
45
|
+
fill: el.style?.fill ?? "none"
|
|
46
|
+
}, el.id));
|
|
47
|
+
else if ((el.kind === "line" || el.kind === "segment") && isLineVal(val)) shapes.push(el.kind === "line" ? /* @__PURE__ */ jsx(Line, {
|
|
48
|
+
from: val.a,
|
|
49
|
+
to: val.b,
|
|
50
|
+
color: color ?? "var(--stage-muted)",
|
|
51
|
+
dashed: el.style?.dashed
|
|
52
|
+
}, el.id) : /* @__PURE__ */ jsx(Segment, {
|
|
53
|
+
from: val.a,
|
|
54
|
+
to: val.b,
|
|
55
|
+
color: color ?? "var(--stage-good)",
|
|
56
|
+
dashed: el.style?.dashed
|
|
57
|
+
}, el.id));
|
|
58
|
+
else if (el.kind === "polygon" && Array.isArray(val)) shapes.push(/* @__PURE__ */ jsx(Polygon, {
|
|
59
|
+
points: val,
|
|
60
|
+
color: color ?? "var(--stage-accent)",
|
|
61
|
+
fill: el.style?.fill ?? "var(--stage-accent)"
|
|
62
|
+
}, el.id));
|
|
63
|
+
else if (el.kind === "measure" && isDerived(el)) {
|
|
64
|
+
const value = typeof val === "number" ? val : NaN;
|
|
65
|
+
const a = point(parentRef(el, 0));
|
|
66
|
+
const b = point(parentRef(el, 1));
|
|
67
|
+
const at = a && b ? vec.midpoint(a, b) : a;
|
|
68
|
+
if (at && Number.isFinite(value)) {
|
|
69
|
+
if (el.def.op === "distance" && a && b) shapes.push(/* @__PURE__ */ jsx(Segment, {
|
|
70
|
+
from: a,
|
|
71
|
+
to: b,
|
|
72
|
+
color: "var(--stage-muted)",
|
|
73
|
+
dashed: true,
|
|
74
|
+
weight: 1.5
|
|
75
|
+
}, `${el.id}-seg`));
|
|
76
|
+
overlays.push(/* @__PURE__ */ jsx(Label, {
|
|
77
|
+
x: at.x,
|
|
78
|
+
y: at.y,
|
|
79
|
+
dy: -8,
|
|
80
|
+
text: `${el.label ? el.label + " = " : ""}${value.toFixed(2)}`,
|
|
81
|
+
color: "var(--stage-warn)",
|
|
82
|
+
size: 13
|
|
83
|
+
}, el.id));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const el of doc.elements) {
|
|
88
|
+
if (el.style?.hidden) continue;
|
|
89
|
+
const val = resolved.values.get(el.id);
|
|
90
|
+
if (el.kind === "note" && isVec2(val)) overlays.push(/* @__PURE__ */ jsx(Label, {
|
|
91
|
+
x: val.x,
|
|
92
|
+
y: val.y,
|
|
93
|
+
text: "free" in el ? el.free.text : "",
|
|
94
|
+
color: el.style?.color ?? "var(--stage-fg)"
|
|
95
|
+
}, el.id));
|
|
96
|
+
else if (el.kind === "point" && isVec2(val)) {
|
|
97
|
+
const selected = opts.selection === el.id;
|
|
98
|
+
if (opts.draggablePoints && !!opts.onPointMove && "free" in el && !!el.free.draggable && "free" in el) {
|
|
99
|
+
const constrain = el.free.constrain === "horizontal" || el.free.constrain === "vertical" ? el.free.constrain : void 0;
|
|
100
|
+
overlays.push(/* @__PURE__ */ jsx(MovableDot, {
|
|
101
|
+
value: val,
|
|
102
|
+
onMove: (p, ph) => opts.onPointMove?.(el.id, p, ph),
|
|
103
|
+
constrain,
|
|
104
|
+
color: el.style?.color ?? "var(--stage-accent)",
|
|
105
|
+
ariaLabel: el.a11y?.label ?? el.label ?? "point"
|
|
106
|
+
}, el.id));
|
|
107
|
+
} else overlays.push(/* @__PURE__ */ jsx(Point, {
|
|
108
|
+
x: val.x,
|
|
109
|
+
y: val.y,
|
|
110
|
+
r: selected ? 7 : 6,
|
|
111
|
+
color: selected ? "var(--stage-warn)" : el.style?.color ?? "var(--stage-accent)"
|
|
112
|
+
}, el.id));
|
|
113
|
+
if (el.label) overlays.push(/* @__PURE__ */ jsx(Label, {
|
|
114
|
+
x: val.x,
|
|
115
|
+
y: val.y,
|
|
116
|
+
dy: -12,
|
|
117
|
+
text: el.label,
|
|
118
|
+
size: 13
|
|
119
|
+
}, `${el.id}-lbl`));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [shapes, overlays] });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
export { renderElements };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Vec2 } from "../core/vec.mjs";
|
|
2
|
+
import { Id, SceneDoc, Val } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/scene/resolve.d.ts
|
|
5
|
+
interface Resolved {
|
|
6
|
+
values: Map<Id, Val>;
|
|
7
|
+
order: Id[];
|
|
8
|
+
errors: Record<Id, string>;
|
|
9
|
+
}
|
|
10
|
+
declare function resolve(doc: SceneDoc, overlay?: ReadonlyMap<Id, Vec2 | number>, prev?: Resolved, simStates?: ReadonlyMap<Id, Record<string, unknown>>): Resolved;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { Resolved, resolve };
|