@classytic/stage 0.1.0 → 0.2.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.
Files changed (86) hide show
  1. package/README.md +2 -2
  2. package/dist/assets/kit/glyphs.d.mts +5 -5
  3. package/dist/assets/kit/glyphs.mjs +4 -4
  4. package/dist/builder/SceneBuilder.mjs +4 -4
  5. package/dist/builder/editor.d.mts +2 -1
  6. package/dist/builder/editor.mjs +14 -4
  7. package/dist/builder/tools.d.mts +1 -1
  8. package/dist/builder/tools.mjs +1 -1
  9. package/dist/chem/index.d.mts +5 -5
  10. package/dist/chem/index.mjs +4 -4
  11. package/dist/circuit/index.d.mts +92 -0
  12. package/dist/circuit/index.mjs +333 -0
  13. package/dist/core/clock.d.mts +1 -1
  14. package/dist/core/clock.mjs +3 -3
  15. package/dist/core/control.d.mts +1 -1
  16. package/dist/core/control.mjs +2 -2
  17. package/dist/core/coords.d.mts +4 -4
  18. package/dist/core/coords.mjs +1 -1
  19. package/dist/core/learner.d.mts +1 -1
  20. package/dist/core/learner.mjs +1 -1
  21. package/dist/core/motion.d.mts +6 -6
  22. package/dist/core/motion.mjs +6 -6
  23. package/dist/core/richText.d.mts +2 -2
  24. package/dist/core/vec.d.mts +1 -1
  25. package/dist/field/index.d.mts +11 -3
  26. package/dist/field/index.mjs +20 -3
  27. package/dist/index.d.mts +3 -1
  28. package/dist/index.mjs +3 -1
  29. package/dist/interaction/MovableDot.d.mts +17 -1
  30. package/dist/interaction/MovableDot.mjs +141 -43
  31. package/dist/interaction/index.d.mts +2 -1
  32. package/dist/interaction/index.mjs +2 -1
  33. package/dist/interaction/useDraggable.d.mts +1 -1
  34. package/dist/interaction/useDraggable.mjs +31 -1
  35. package/dist/interaction/usePressSpring.d.mts +24 -0
  36. package/dist/interaction/usePressSpring.mjs +67 -0
  37. package/dist/logic/ast.d.mts +1 -1
  38. package/dist/logic/index.mjs +8 -3
  39. package/dist/logic/minimize.d.mts +2 -2
  40. package/dist/logic/minimize.mjs +56 -18
  41. package/dist/logic/table.mjs +1 -1
  42. package/dist/math/ast.d.mts +1 -1
  43. package/dist/math/ast.mjs +1 -1
  44. package/dist/math/calculus.mjs +68 -9
  45. package/dist/math/compile.d.mts +8 -0
  46. package/dist/math/compile.mjs +40 -0
  47. package/dist/math/defs.mjs +1 -1
  48. package/dist/math/index.d.mts +4 -3
  49. package/dist/math/index.mjs +4 -3
  50. package/dist/math/parse.mjs +2 -2
  51. package/dist/math/tokenize.mjs +1 -1
  52. package/dist/primitives/CanvasLayer.mjs +3 -3
  53. package/dist/primitives/Grid.d.mts +12 -1
  54. package/dist/primitives/Grid.mjs +15 -9
  55. package/dist/primitives/Label.d.mts +1 -1
  56. package/dist/primitives/Label.mjs +1 -1
  57. package/dist/primitives/Tex.mjs +2 -2
  58. package/dist/scene/Scene.mjs +1 -1
  59. package/dist/scene/assets.d.mts +2 -2
  60. package/dist/scene/assets.mjs +2 -2
  61. package/dist/scene/commands.d.mts +10 -1
  62. package/dist/scene/commands.mjs +42 -2
  63. package/dist/scene/evaluators.mjs +2 -2
  64. package/dist/scene/index.d.mts +2 -2
  65. package/dist/scene/index.mjs +2 -2
  66. package/dist/scene/migrate.mjs +1 -1
  67. package/dist/scene/sims.mjs +1 -1
  68. package/dist/scene/types.d.mts +4 -4
  69. package/dist/sim/particles.d.mts +2 -2
  70. package/dist/sim/rate.d.mts +4 -4
  71. package/dist/sim/rate.mjs +1 -1
  72. package/dist/sim/registry.d.mts +1 -1
  73. package/dist/sim/sampler.d.mts +5 -5
  74. package/dist/sim/thermal.d.mts +3 -3
  75. package/dist/sim/thermal.mjs +2 -2
  76. package/dist/sim/types.d.mts +2 -2
  77. package/dist/sim/wave.d.mts +2 -2
  78. package/dist/sim/wave.mjs +2 -2
  79. package/dist/steps/index.d.mts +1 -1
  80. package/dist/steps/index.mjs +3 -3
  81. package/dist/thermo/index.d.mts +1 -1
  82. package/dist/thermo/index.mjs +1 -1
  83. package/dist/view/Stage.mjs +2 -2
  84. package/dist/view/useInView.mjs +1 -1
  85. package/package.json +8 -4
  86. package/styles.css +23 -0
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  **Domain‑neutral visual primitive engine for the web.** Declarative SVG diagram/math
4
4
  primitives, draggable handles, a math↔pixel coordinate system, theming, a parametric
5
5
  asset/glyph kit, a serializable `SceneDoc` graph (resolver + command/undo), and a
6
- `LessonDoc` sequence engine. Reactive, web‑native, SSR‑safe, and agent‑drivable — the
6
+ stepped‑lesson sequence engine (`StepSpec`). Reactive, web‑native, SSR‑safe, and agent‑drivable — the
7
7
  render foundation under [`@classytic/labs`](https://github.com/classytic/labs).
8
8
 
9
9
  ```bash
@@ -27,7 +27,7 @@ your bundle pulls only what it uses (ESM, per‑file emit; `sideEffects` are sco
27
27
  | `@classytic/stage/builder` | `Editor`, `SceneBuilder`, `Palette`, construction `*_TOOLS` |
28
28
  | `@classytic/stage/assets` | `StageAssetDefs` + the glyph kit (`XBlockGlyph`, `WeightGlyph`, `BucketGlyph`, `HangerHook`) |
29
29
  | `@classytic/stage/math` | dependency‑free expression engine (`compileExpr`, `differentiate`, `toLatex`…) |
30
- | `@classytic/stage/lesson` | `LessonProvider`, `useLessonProgress`, `LessonStepScope` (sequence + gating + progress) |
30
+ | `@classytic/stage/steps` | `StepProgressProvider`, `useStepProgress`, `StepScope` (step sequence + gating + progress) |
31
31
  | `@classytic/stage/styles.css` | theme tokens + control‑kit CSS (import once in global CSS) |
32
32
 
33
33
  ## Quick start
@@ -8,7 +8,7 @@ interface GlyphBox {
8
8
  hpx: number;
9
9
  label: string;
10
10
  }
11
- /** The UNKNOWN a crisp rounded tile with an italic label (e.g. "2x"). */
11
+ /** The UNKNOWN, a crisp rounded tile with an italic label (e.g. "2x"). */
12
12
  declare function XBlockGlyph({
13
13
  cx,
14
14
  top,
@@ -16,7 +16,7 @@ declare function XBlockGlyph({
16
16
  hpx,
17
17
  label
18
18
  }: GlyphBox): ReactNode;
19
- /** A container of UNKNOWN amount a pail, brand-colored (it IS an unknown, like
19
+ /** A container of UNKNOWN amount, a pail, brand-colored (it IS an unknown, like
20
20
  * the tile), labelled "?" until revealed. Built with real form: one light
21
21
  * direction (top-left), 2-tone shading for volume (gradient body + a soft
22
22
  * right-side shadow + a left specular streak), a rim with visible thickness
@@ -33,13 +33,13 @@ interface HangerHookProps {
33
33
  /** Attach point on the beam/arm (pixels). */
34
34
  topX: number;
35
35
  topY: number;
36
- /** Attach point on the load the top-centre of the glyph it carries (pixels). */
36
+ /** Attach point on the load, the top-centre of the glyph it carries (pixels). */
37
37
  botX: number;
38
38
  botY: number;
39
39
  }
40
40
  /**
41
41
  * A suspension: a thin eye on the beam, a taut thread, and an S-hook that grips
42
- * the load the realistic way a weight hangs from an arm (replaces the old
42
+ * the load, the realistic way a weight hangs from an arm (replaces the old
43
43
  * bare "line + dot"). Pure pixel glyph: callers project math→px first. Layered
44
44
  * edge/metal/sheen strokes match the beam's metallic read.
45
45
  */
@@ -49,7 +49,7 @@ declare function HangerHook({
49
49
  botX,
50
50
  botY
51
51
  }: HangerHookProps): ReactNode;
52
- /** A KNOWN value a clean flat coin with the number. */
52
+ /** A KNOWN value, a clean flat coin with the number. */
53
53
  declare function WeightGlyph({
54
54
  cx,
55
55
  top,
@@ -3,7 +3,7 @@
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
 
5
5
  //#region src/assets/kit/glyphs.tsx
6
- /** The UNKNOWN a crisp rounded tile with an italic label (e.g. "2x"). */
6
+ /** The UNKNOWN, a crisp rounded tile with an italic label (e.g. "2x"). */
7
7
  function XBlockGlyph({ cx, top, wpx, hpx, label }) {
8
8
  const s = Math.min(wpx, hpx);
9
9
  const x0 = cx - s / 2;
@@ -50,7 +50,7 @@ function XBlockGlyph({ cx, top, wpx, hpx, label }) {
50
50
  })
51
51
  ] });
52
52
  }
53
- /** A container of UNKNOWN amount a pail, brand-colored (it IS an unknown, like
53
+ /** A container of UNKNOWN amount, a pail, brand-colored (it IS an unknown, like
54
54
  * the tile), labelled "?" until revealed. Built with real form: one light
55
55
  * direction (top-left), 2-tone shading for volume (gradient body + a soft
56
56
  * right-side shadow + a left specular streak), a rim with visible thickness
@@ -156,7 +156,7 @@ function BucketGlyph({ cx, top, wpx, hpx, label }) {
156
156
  }
157
157
  /**
158
158
  * A suspension: a thin eye on the beam, a taut thread, and an S-hook that grips
159
- * the load the realistic way a weight hangs from an arm (replaces the old
159
+ * the load, the realistic way a weight hangs from an arm (replaces the old
160
160
  * bare "line + dot"). Pure pixel glyph: callers project math→px first. Layered
161
161
  * edge/metal/sheen strokes match the beam's metallic read.
162
162
  */
@@ -210,7 +210,7 @@ function HangerHook({ topX, topY, botX, botY }) {
210
210
  })
211
211
  ] });
212
212
  }
213
- /** A KNOWN value a clean flat coin with the number. */
213
+ /** A KNOWN value, a clean flat coin with the number. */
214
214
  function WeightGlyph({ cx, top, wpx, hpx, label }) {
215
215
  const r = Math.min(wpx, hpx) / 2;
216
216
  const cy = top + r;
@@ -14,9 +14,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
14
14
 
15
15
  //#region src/builder/SceneBuilder.tsx
16
16
  /**
17
- * <SceneBuilder> the click-to-construct authoring surface. Pick a tool, click
17
+ * <SceneBuilder>, the click-to-construct authoring surface. Pick a tool, click
18
18
  * the canvas: every action funnels through the Editor command stack (undo/redo +
19
- * the agent API). Output is a SceneDoc (onSave) the same JSON the player
19
+ * the agent API). Output is a SceneDoc (onSave), the same JSON the player
20
20
  * renders and the DB stores. Free points drag only in Select mode, so clicks in
21
21
  * other tools go to the tool, not a drag.
22
22
  */
@@ -236,7 +236,7 @@ function SceneBuilder({ initial, onSave, view, height = 440, tools, authoring =
236
236
  cursor: "pointer",
237
237
  fontWeight: 600
238
238
  },
239
- children: "Pedagogy objectives · hints · difficulty"
239
+ children: "Pedagogy, objectives · hints · difficulty"
240
240
  }), /* @__PURE__ */ jsxs("div", {
241
241
  style: {
242
242
  display: "grid",
@@ -306,7 +306,7 @@ function SceneBuilder({ initial, onSave, view, height = 440, tools, authoring =
306
306
  },
307
307
  children: [/* @__PURE__ */ jsx("option", {
308
308
  value: "",
309
- children: ""
309
+ children: ", "
310
310
  }), [
311
311
  1,
312
312
  2,
@@ -21,7 +21,8 @@ declare class Editor {
21
21
  getResolved(): Resolved;
22
22
  subscribe(fn: () => void): () => void;
23
23
  private emit;
24
- /** Apply a command. The ONLY mutation entry point. */
24
+ /** Apply a command. The ONLY mutation entry point. Validates first: an invalid command (bad
25
+ * id, dangling binding, missing target) is REJECTED with a reason and the doc is untouched. */
25
26
  dispatch(cmd: Command, opts?: DispatchOpts): CommandResult;
26
27
  /** Group boundary marker (label-only in this impl; batch commands group atomically). */
27
28
  mark(_label?: string): void;
@@ -1,12 +1,12 @@
1
1
  'use client';
2
2
 
3
3
  import { resolve } from "../scene/resolve.mjs";
4
- import { applyCommand, inverse } from "../scene/commands.mjs";
4
+ import { applyCommand, createdIds, inverse, validateCommand } from "../scene/commands.mjs";
5
5
  import { useEffect, useReducer, useRef, useState } from "react";
6
6
 
7
7
  //#region src/builder/editor.ts
8
8
  /**
9
- * Editor the single funnel for ALL scene mutations (builder tools, agents,
9
+ * Editor, the single funnel for ALL scene mutations (builder tools, agents,
10
10
  * undo/redo, the control-surface bridge). Commands ARE the agent action API:
11
11
  * dispatch(cmd) is exactly what a human tool, a voice agent, and an undo all call.
12
12
  * Drag is an ephemeral overlay layer; updateDrag writes no command (no undo, no
@@ -48,8 +48,14 @@ var Editor = class {
48
48
  emit() {
49
49
  this.listeners.forEach((l) => l());
50
50
  }
51
- /** Apply a command. The ONLY mutation entry point. */
51
+ /** Apply a command. The ONLY mutation entry point. Validates first: an invalid command (bad
52
+ * id, dangling binding, missing target) is REJECTED with a reason and the doc is untouched. */
52
53
  dispatch(cmd, opts = {}) {
54
+ const error = validateCommand(this.doc, cmd);
55
+ if (error) return {
56
+ ok: false,
57
+ error
58
+ };
53
59
  const inv = inverse(cmd, this.doc);
54
60
  this.doc = applyCommand(this.doc, cmd);
55
61
  if (opts.history !== "ignore") {
@@ -60,7 +66,11 @@ var Editor = class {
60
66
  this.redoStack = [];
61
67
  }
62
68
  this.emit();
63
- return { ok: true };
69
+ const ids = createdIds(cmd);
70
+ return ids.length ? {
71
+ ok: true,
72
+ createdIds: ids
73
+ } : { ok: true };
64
74
  }
65
75
  /** Group boundary marker (label-only in this impl; batch commands group atomically). */
66
76
  mark(_label) {}
@@ -36,7 +36,7 @@ declare const MIDPOINT: Tool;
36
36
  declare const INTERSECT: Tool;
37
37
  declare const MEASURE: Tool;
38
38
  declare const DELETE: Tool;
39
- /** A free scalar parameter appears as a live slider in the authoring strip. */
39
+ /** A free scalar parameter, appears as a live slider in the authoring strip. */
40
40
  declare const SCALAR: Tool;
41
41
  /** A free text note placed in the scene. */
42
42
  declare const NOTE: Tool;
@@ -224,7 +224,7 @@ const DELETE = {
224
224
  });
225
225
  }
226
226
  };
227
- /** A free scalar parameter appears as a live slider in the authoring strip. */
227
+ /** A free scalar parameter, appears as a live slider in the authoring strip. */
228
228
  const SCALAR = {
229
229
  id: "scalar",
230
230
  icon: "scalar",
@@ -1,6 +1,6 @@
1
1
  //#region src/chem/index.d.ts
2
2
  /**
3
- * `chem` acid–base / pH AND electrochemistry / Nernst, as a PURE kernel (no
3
+ * `chem`, acid–base / pH AND electrochemistry / Nernst, as a PURE kernel (no
4
4
  * React, no pixels). The engine behind titration curves, pH problems, and galvanic
5
5
  * cells.
6
6
  *
@@ -11,8 +11,8 @@
11
11
  *
12
12
  * where n_a is the acid initially present, n_b the strong base added, V the total
13
13
  * volume. A strong acid is just the K_a → ∞ limit (fully dissociated). Solving the
14
- * balance (monotonic in h → bisection) is robust everywhere initial point, buffer
15
- * region, equivalence, and past it with no piecewise approximations to get wrong.
14
+ * balance (monotonic in h → bisection) is robust everywhere, initial point, buffer
15
+ * region, equivalence, and past it, with no piecewise approximations to get wrong.
16
16
  *
17
17
  * Concentrations in mol/L, volumes in litres. Currently models an ACID analyte
18
18
  * titrated by a STRONG BASE (covers strong-acid and weak-acid curves).
@@ -81,7 +81,7 @@ interface CellResult {
81
81
  declare function galvanicCell(x: HalfCell, y: HalfCell, T?: number): CellResult;
82
82
  /** Arrhenius rate constant k = A·e^(−Ea/RT). */
83
83
  declare function arrhenius(A: number, Ea: number, T: number): number;
84
- /** Ratio k(T)/k(Tref) at fixed Ea the stable way to scale a rate without a raw A. */
84
+ /** Ratio k(T)/k(Tref) at fixed Ea, the stable way to scale a rate without a raw A. */
85
85
  declare function arrheniusRatio(Ea: number, T: number, Tref?: number): number;
86
86
  /** Fraction of molecules with energy ≥ Ea (Boltzmann) ≈ e^(−Ea/RT). */
87
87
  declare function fractionAboveEa(Ea: number, T: number): number;
@@ -94,7 +94,7 @@ interface StoichSpecies {
94
94
  name: string;
95
95
  /** Stoichiometric coefficient in the balanced equation. */
96
96
  coeff: number;
97
- /** Molar mass, g/mol (optional enables grams in the result). */
97
+ /** Molar mass, g/mol (optional, enables grams in the result). */
98
98
  molarMass?: number;
99
99
  }
100
100
  interface StoichResult {
@@ -1,6 +1,6 @@
1
1
  //#region src/chem/index.ts
2
2
  /**
3
- * `chem` acid–base / pH AND electrochemistry / Nernst, as a PURE kernel (no
3
+ * `chem`, acid–base / pH AND electrochemistry / Nernst, as a PURE kernel (no
4
4
  * React, no pixels). The engine behind titration curves, pH problems, and galvanic
5
5
  * cells.
6
6
  *
@@ -11,8 +11,8 @@
11
11
  *
12
12
  * where n_a is the acid initially present, n_b the strong base added, V the total
13
13
  * volume. A strong acid is just the K_a → ∞ limit (fully dissociated). Solving the
14
- * balance (monotonic in h → bisection) is robust everywhere initial point, buffer
15
- * region, equivalence, and past it with no piecewise approximations to get wrong.
14
+ * balance (monotonic in h → bisection) is robust everywhere, initial point, buffer
15
+ * region, equivalence, and past it, with no piecewise approximations to get wrong.
16
16
  *
17
17
  * Concentrations in mol/L, volumes in litres. Currently models an ACID analyte
18
18
  * titrated by a STRONG BASE (covers strong-acid and weak-acid curves).
@@ -90,7 +90,7 @@ function galvanicCell(x, y, T = T_STD) {
90
90
  function arrhenius(A, Ea, T) {
91
91
  return A * Math.exp(-Ea / (R * T));
92
92
  }
93
- /** Ratio k(T)/k(Tref) at fixed Ea the stable way to scale a rate without a raw A. */
93
+ /** Ratio k(T)/k(Tref) at fixed Ea, the stable way to scale a rate without a raw A. */
94
94
  function arrheniusRatio(Ea, T, Tref = T_STD) {
95
95
  return Math.exp(-(Ea / R) * (1 / T - 1 / Tref));
96
96
  }
@@ -0,0 +1,92 @@
1
+ //#region src/circuit/index.d.ts
2
+ /**
3
+ * @classytic/stage/circuit, a small, dependency-free circuit-solver kernel (a
4
+ * mini-SPICE) built on Modified Nodal Analysis (MNA). Like the `field` and `math`
5
+ * kernels it is pure, deterministic engine machinery: you describe a netlist of
6
+ * elements (resistors, sources, capacitors, inductors) and it returns the node
7
+ * voltages and branch currents, the correct numbers, so a current-electricity
8
+ * lab shows real results instead of hand-rolled per-lab arithmetic.
9
+ *
10
+ * • solveDC , DC operating point (capacitors open, inductors short).
11
+ * • solveTransient, time-stepped response (RC / RL / RLC) via Backward-Euler
12
+ * companion models: each reactive element becomes a
13
+ * conductance Geq in parallel with a current source Ieq each
14
+ * step, exactly how real simulators integrate the ODEs.
15
+ *
16
+ * Node 0 is ground (the reference). MNA stamps are additive, so parallel elements
17
+ * just sum. Nonlinear devices (diodes / transistors via Newton-Raphson) are the
18
+ * next layer and slot into the same stamping helpers.
19
+ *
20
+ * Conventions (validated against the MNA / Qucs companion-model references):
21
+ * • Resistor R between (n1,n2): conductance g = 1/R.
22
+ * • Current source I: drives `value` amps from n1 to n2 (injected into n2).
23
+ * • Voltage source V: value volts, n1 is + relative to n2 (adds a branch current
24
+ * unknown). Its solved current is positive flowing n1 → n2 inside the source.
25
+ */
26
+ type NodeId = number;
27
+ interface Elem {
28
+ kind: 'R' | 'V' | 'I' | 'C' | 'L' | 'D' | 'M';
29
+ /** diode: n1=anode, n2=cathode. NMOS 'M': n1=drain, n2=source, n3=gate. */
30
+ n1: NodeId;
31
+ n2: NodeId;
32
+ /** gate node for an NMOS 'M'. */
33
+ n3?: NodeId;
34
+ /** ohms (R) / volts (V) / amps (I) / farads (C) / henries (L). Ignored for D / M. */
35
+ value: number;
36
+ /** diode saturation current Is (default 1e-12 A). */
37
+ is?: number;
38
+ /** diode ideality factor n (default 1). */
39
+ nIdeal?: number;
40
+ /** MOSFET threshold voltage Vth (default 2 V; for a PMOS the magnitude is used). */
41
+ vth?: number;
42
+ /** MOSFET transconductance parameter k = µCox·W/L (default 0.5 A/V²). */
43
+ k?: number;
44
+ /** P-channel MOSFET (conducts when the gate is LOW vs the source). Default NMOS. */
45
+ pmos?: boolean;
46
+ /** optional label, used to key the returned branch currents. */
47
+ id?: string;
48
+ }
49
+ /** Solve A x = b by Gaussian elimination with partial pivoting. Returns null if singular. */
50
+ declare function solveLinear(A: number[][], b: number[]): number[] | null;
51
+ interface DCResult {
52
+ /** node voltages indexed by node id; [0] is ground = 0. */
53
+ nodeV: number[];
54
+ /** current through each branch element (V sources, and inductors), keyed by id. */
55
+ current: Record<string, number>;
56
+ ok: boolean;
57
+ }
58
+ /** DC operating point: capacitors open, inductors short. Routes to the nonlinear solver for diodes / MOSFETs. */
59
+ declare function solveDC(elems: readonly Elem[]): DCResult;
60
+ /**
61
+ * Nonlinear DC via Newton-Raphson: each iteration linearizes every nonlinear device
62
+ * (diode Shockley with pnjlim limiting; NMOS square-law about the previous node
63
+ * voltages) into a companion conductance + current source, solves the linear system,
64
+ * and repeats until the solution settles.
65
+ */
66
+ declare function solveDCNonlinear(elems: readonly Elem[], opts?: {
67
+ maxIter?: number;
68
+ tol?: number;
69
+ }): DCResult;
70
+ /** Current through an element given solved node voltages (R/I directly; C/L need state). */
71
+ declare function elementCurrent(e: Elem, nodeV: number[]): number;
72
+ interface TransientStep {
73
+ t: number;
74
+ nodeV: number[];
75
+ }
76
+ interface TransientOpts {
77
+ dt: number;
78
+ steps: number;
79
+ /** initial voltages across reactive elements, keyed by element index (default 0). */
80
+ initialV?: Map<number, number>;
81
+ }
82
+ /**
83
+ * Time-stepped transient (Backward Euler). Returns the node-voltage trajectory,
84
+ * including t = 0. Reactive elements use companion models rebuilt every step.
85
+ */
86
+ declare function solveTransient(elems: readonly Elem[], opts: TransientOpts): TransientStep[];
87
+ /** Equivalent resistance of resistors in series. */
88
+ declare function seriesR(...rs: number[]): number;
89
+ /** Equivalent resistance of resistors in parallel. */
90
+ declare function parallelR(...rs: number[]): number;
91
+ //#endregion
92
+ export { DCResult, Elem, NodeId, TransientOpts, TransientStep, elementCurrent, parallelR, seriesR, solveDC, solveDCNonlinear, solveLinear, solveTransient };