simple-circuit-engine 0.0.12 → 0.0.14

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 (99) hide show
  1. package/AGENTS.md +9 -6
  2. package/CLAUDE.md +2 -0
  3. package/README.md +8 -8
  4. package/dist/core/index.js +109 -74
  5. package/dist/core/setup.d.ts +18 -0
  6. package/dist/core/simulation/behaviors/arithmetic/AdderBehavior.d.ts +28 -0
  7. package/dist/core/simulation/behaviors/arithmetic/ArithmeticBehaviorMixin.d.ts +63 -0
  8. package/dist/core/simulation/behaviors/arithmetic/EightBitAdderBehavior.d.ts +51 -0
  9. package/dist/core/simulation/behaviors/arithmetic/EightBitOnesComplementBehavior.d.ts +29 -0
  10. package/dist/core/simulation/behaviors/arithmetic/HalfAdderBehavior.d.ts +22 -0
  11. package/dist/core/simulation/behaviors/arithmetic/index.d.ts +7 -0
  12. package/dist/core/simulation/behaviors/index.d.ts +14 -0
  13. package/dist/core/simulation/behaviors/interface/EightInputBehavior.d.ts +9 -0
  14. package/dist/core/simulation/behaviors/interface/EightLightBehavior.d.ts +9 -0
  15. package/dist/core/simulation/behaviors/interface/FourInputBehavior.d.ts +9 -0
  16. package/dist/core/simulation/behaviors/interface/FourLightBehavior.d.ts +9 -0
  17. package/dist/core/simulation/behaviors/interface/InputBehaviorMixin.d.ts +37 -0
  18. package/dist/core/simulation/behaviors/interface/LightBehaviorMixin.d.ts +60 -0
  19. package/dist/core/simulation/behaviors/interface/OneInputBehavior.d.ts +9 -0
  20. package/dist/core/simulation/behaviors/interface/OneLightBehavior.d.ts +9 -0
  21. package/dist/core/simulation/behaviors/interface/TwoInputBehavior.d.ts +9 -0
  22. package/dist/core/simulation/behaviors/interface/TwoLightBehavior.d.ts +9 -0
  23. package/dist/core/simulation/behaviors/interface/index.d.ts +0 -0
  24. package/dist/core/simulation/states/arithmetic/AdderState.d.ts +16 -0
  25. package/dist/core/simulation/states/arithmetic/ArithmeticState.d.ts +53 -0
  26. package/dist/core/simulation/states/arithmetic/EightBitAdderState.d.ts +25 -0
  27. package/dist/core/simulation/states/arithmetic/EightBitOnesComplementState.d.ts +18 -0
  28. package/dist/core/simulation/states/arithmetic/HalfAdderState.d.ts +16 -0
  29. package/dist/core/simulation/states/arithmetic/index.d.ts +7 -0
  30. package/dist/core/simulation/states/index.d.ts +15 -0
  31. package/dist/core/simulation/states/interface/EightInputState.d.ts +6 -0
  32. package/dist/core/simulation/states/interface/EightLightState.d.ts +6 -0
  33. package/dist/core/simulation/states/interface/FourInputState.d.ts +6 -0
  34. package/dist/core/simulation/states/interface/FourLightState.d.ts +6 -0
  35. package/dist/core/simulation/states/interface/InputState.d.ts +45 -0
  36. package/dist/core/simulation/states/interface/LightState.d.ts +54 -0
  37. package/dist/core/simulation/states/interface/OneInputState.d.ts +6 -0
  38. package/dist/core/simulation/states/interface/OneLightState.d.ts +6 -0
  39. package/dist/core/simulation/states/interface/TwoInputState.d.ts +6 -0
  40. package/dist/core/simulation/states/interface/TwoLightState.d.ts +6 -0
  41. package/dist/core/simulation/types.d.ts +10 -2
  42. package/dist/core/topology/Component.d.ts +6 -1
  43. package/dist/core/topology/ENode.d.ts +7 -2
  44. package/dist/core/topology/index.d.ts +2 -0
  45. package/dist/core/topology/networkTraversal.d.ts +50 -0
  46. package/dist/core/topology/types.d.ts +31 -6
  47. package/dist/core-HH6iRWtB.js +4671 -0
  48. package/dist/core-HH6iRWtB.js.map +1 -0
  49. package/dist/i18n/index.d.ts +1158 -0
  50. package/dist/i18n/locales/en.json.d.ts +366 -0
  51. package/dist/i18n/locales/fr.json.d.ts +366 -0
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.js +172 -118
  54. package/dist/scene/CircuitEngine.d.ts +49 -4
  55. package/dist/scene/index.d.ts +6 -2
  56. package/dist/scene/index.js +62 -45
  57. package/dist/scene/setup.d.ts +18 -0
  58. package/dist/scene/shared/AbstractCircuitController.d.ts +11 -3
  59. package/dist/scene/shared/HoverManager.d.ts +15 -0
  60. package/dist/scene/shared/components/arithmetic/AdderVisualFactory.d.ts +54 -0
  61. package/dist/scene/shared/components/arithmetic/EightBitAdderVisualFactory.d.ts +45 -0
  62. package/dist/scene/shared/components/arithmetic/EightBitOnesComplementVisualFactory.d.ts +63 -0
  63. package/dist/scene/shared/components/arithmetic/HalfAdderVisualFactory.d.ts +55 -0
  64. package/dist/scene/shared/components/arithmetic/index.d.ts +4 -0
  65. package/dist/scene/shared/components/index.d.ts +14 -0
  66. package/dist/scene/shared/components/interface/EightInputVisualFactory.d.ts +15 -0
  67. package/dist/scene/shared/components/interface/EightLightVisualFactory.d.ts +15 -0
  68. package/dist/scene/shared/components/interface/FourInputVisualFactory.d.ts +15 -0
  69. package/dist/scene/shared/components/interface/FourLightVisualFactory.d.ts +15 -0
  70. package/dist/scene/shared/components/interface/InputVisualFactoryBase.d.ts +50 -0
  71. package/dist/scene/shared/components/interface/LightVisualFactoryBase.d.ts +46 -0
  72. package/dist/scene/shared/components/interface/OneInputVisualFactory.d.ts +15 -0
  73. package/dist/scene/shared/components/interface/OneLightVisualFactory.d.ts +15 -0
  74. package/dist/scene/shared/components/interface/TwoInputVisualFactory.d.ts +15 -0
  75. package/dist/scene/shared/components/interface/TwoLightVisualFactory.d.ts +15 -0
  76. package/dist/scene/shared/types.d.ts +34 -4
  77. package/dist/scene/shared/utils/ControlsUtils.d.ts +1 -1
  78. package/dist/scene/shared/utils/GeometryUtils.d.ts +111 -0
  79. package/dist/scene/static/CircuitController.d.ts +13 -1
  80. package/dist/scene/static/tools/BuildTool.d.ts +81 -0
  81. package/dist/scene/static/tools/ComponentPickerWidget.d.ts +7 -0
  82. package/dist/scene/static/tools/ConfigPanelWidget.d.ts +14 -0
  83. package/dist/scene/static/tools/MultiWiringPlacement.d.ts +40 -0
  84. package/dist/scene/widgets/HelpWidget.d.ts +13 -0
  85. package/dist/scene/widgets/ModeWidget.d.ts +16 -0
  86. package/dist/scene/widgets/MultiWiringWidget.d.ts +21 -0
  87. package/dist/scene/{static → widgets}/PinTooltipWidget.d.ts +7 -1
  88. package/dist/scene/widgets/SimulationPlayerWidget.d.ts +62 -0
  89. package/dist/scene/widgets/ToolsWidget.d.ts +18 -0
  90. package/dist/scene/widgets/WidgetsManager.d.ts +65 -0
  91. package/dist/scene/widgets/assets/icons.d.ts +20 -0
  92. package/dist/scene/widgets/index.d.ts +9 -0
  93. package/dist/scene/widgets/styles.d.ts +33 -0
  94. package/dist/{scene-CVsDdySt.js → scene-C1xhdw_B.js} +3993 -772
  95. package/dist/scene-C1xhdw_B.js.map +1 -0
  96. package/package.json +14 -9
  97. package/dist/core-Bjta9Y7_.js +0 -2707
  98. package/dist/core-Bjta9Y7_.js.map +0 -1
  99. package/dist/scene-CVsDdySt.js.map +0 -1
@@ -0,0 +1,60 @@
1
+ import { Component } from '../../../topology/Component';
2
+ import { ComponentState } from '../../states/ComponentState';
3
+ import { INodeElectricalState } from '../../states/types';
4
+ import { UUID } from '../../../utils/types';
5
+ import { ENodeSourceType } from '../../../topology/types';
6
+ import { IScheduledEvent } from '../../types';
7
+ import { IBehaviorResult } from '../types';
8
+ import { ComponentBehaviorMixin } from '../ComponentBehavior';
9
+ import { LightState } from '../../states/interface/LightState';
10
+ /**
11
+ * Factorises the plumbing shared by `OneLight`, `TwoLight`, `FourLight` and
12
+ * `EightLight` behaviors.
13
+ *
14
+ * These components mirror their `input-i` pins onto matching `output-i` pins
15
+ * with a per-light `transitionSpan` delay. The state encodes the current
16
+ * outputs as a hex value (e.g. `'5'` = `0101` for FourLight); while at least
17
+ * one light is moving the state literal is `'moving'` and a parameter map
18
+ * tracks each pending light (`${index}` → `${target}-${startTick}-${endTick}`)
19
+ * plus the actual driving value in `prevState`.
20
+ *
21
+ * Guards (run first in `onPinsChange`):
22
+ * - Vcc loss collapses the state to `allLowState` and clears all pending.
23
+ * - Any ill-defined logic input switches the state to `'indeterminate'`.
24
+ *
25
+ * Concurrency model (per-light, independent transitions):
26
+ * - When an input changes, the target output bit is recomputed; if it differs
27
+ * from the currently-driving (or already-pending) target a `lightChanged`
28
+ * event is scheduled with a per-light span.
29
+ * - If the same input toggles while its light is still moving, the symmetric
30
+ * transition pattern shortens the new span to `Math.max(prevEnd - prevStart, 1)`
31
+ * and the in-flight event becomes a no-op (its readyAtTick no longer matches
32
+ * the pending entry).
33
+ * - `shouldCancelPending: false` outside guards — other lights' transitions
34
+ * keep their schedule.
35
+ *
36
+ * @public
37
+ */
38
+ export declare abstract class LightBehaviorMixin extends ComponentBehaviorMixin {
39
+ onPinsChange(component: Component, state: ComponentState, nodeStates: ReadonlyMap<UUID, INodeElectricalState>, targetTick: number): IBehaviorResult;
40
+ onEventFiring(_component: Component, state: ComponentState, event: IScheduledEvent): IBehaviorResult;
41
+ allowConductivity(component: Component, state: ComponentState, _conductivityType: ENodeSourceType, pinId: string, otherPinId: string): boolean;
42
+ /**
43
+ * On vcc loss: drop all outputs low immediately and clear any pending
44
+ * transitions. Returns `null` when vcc is present so callers can proceed.
45
+ */
46
+ protected vccGuardBehavior(state: LightState, pinStates: Map<string, INodeElectricalState>, targetTick: number): IBehaviorResult | null;
47
+ /**
48
+ * Scan all logic inputs; if any is ill-defined (both voltage and ground, or
49
+ * neither), switch to `'indeterminate'` immediately and clear any pending
50
+ * transitions. Otherwise returns `null` so the caller can proceed.
51
+ */
52
+ protected nonLogicInputGuardBehavior(state: LightState, pinStates: Map<string, INodeElectricalState>, targetTick: number): IBehaviorResult | null;
53
+ /**
54
+ * For each logic input, compute the desired output bit and schedule a
55
+ * per-light `lightChanged` event whenever that bit differs from the current
56
+ * effective (or already-pending) target.
57
+ */
58
+ protected scheduleInputTransitions(component: Component, state: LightState, pinStates: Map<string, INodeElectricalState>, targetTick: number): IBehaviorResult;
59
+ protected noChange(state: ComponentState): IBehaviorResult;
60
+ }
@@ -0,0 +1,9 @@
1
+ import { Component } from '../../../topology/Component';
2
+ import { ComponentState } from '../../states/ComponentState';
3
+ import { IComponentBehavior } from '../types';
4
+ import { InputBehaviorMixin } from './InputBehaviorMixin';
5
+ /** Single-switch user input. See {@link InputBehaviorMixin}. */
6
+ export declare class OneInputBehavior extends InputBehaviorMixin implements IComponentBehavior {
7
+ constructor();
8
+ createInitialState(component: Component): ComponentState;
9
+ }
@@ -0,0 +1,9 @@
1
+ import { Component } from '../../../topology/Component';
2
+ import { ComponentState } from '../../states/ComponentState';
3
+ import { IComponentBehavior } from '../types';
4
+ import { LightBehaviorMixin } from './LightBehaviorMixin';
5
+ /** Single-light input mirror. See {@link LightBehaviorMixin}. */
6
+ export declare class OneLightBehavior extends LightBehaviorMixin implements IComponentBehavior {
7
+ constructor();
8
+ createInitialState(component: Component): ComponentState;
9
+ }
@@ -0,0 +1,9 @@
1
+ import { Component } from '../../../topology/Component';
2
+ import { ComponentState } from '../../states/ComponentState';
3
+ import { IComponentBehavior } from '../types';
4
+ import { InputBehaviorMixin } from './InputBehaviorMixin';
5
+ /** Two-switch user input. See {@link InputBehaviorMixin}. */
6
+ export declare class TwoInputBehavior extends InputBehaviorMixin implements IComponentBehavior {
7
+ constructor();
8
+ createInitialState(component: Component): ComponentState;
9
+ }
@@ -0,0 +1,9 @@
1
+ import { Component } from '../../../topology/Component';
2
+ import { ComponentState } from '../../states/ComponentState';
3
+ import { IComponentBehavior } from '../types';
4
+ import { LightBehaviorMixin } from './LightBehaviorMixin';
5
+ /** Two-light input mirror. See {@link LightBehaviorMixin}. */
6
+ export declare class TwoLightBehavior extends LightBehaviorMixin implements IComponentBehavior {
7
+ constructor();
8
+ createInitialState(component: Component): ComponentState;
9
+ }
@@ -0,0 +1,16 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { ArithmeticState } from './ArithmeticState';
3
+ /**
4
+ * Simulation state for Full Adder components.
5
+ *
6
+ * Hex-encoded stable states: `'0'` (both low), `'1'` (sum high),
7
+ * `'2'` (carry high), `'3'` (both high). All four are reachable;
8
+ * in particular `A = B = carryIn = 1` yields `'3'`.
9
+ *
10
+ * @public
11
+ */
12
+ export declare class AdderState extends ArithmeticState {
13
+ constructor(componentId: UUID, initialState?: string);
14
+ get sumHigh(): boolean;
15
+ get carryOutHigh(): boolean;
16
+ }
@@ -0,0 +1,53 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { ComponentState } from '../ComponentState';
3
+ /**
4
+ * Base simulation state for arithmetic components (half adder, full adder and
5
+ * future multi-bit adders, multiplexers, ...).
6
+ *
7
+ * Stable states are encoded as a zero-padded hexadecimal string where each
8
+ * bit position maps to one logic output. Simple components use one bit per
9
+ * output in declaration order (bit 0 = first logicOutput). For example a
10
+ * half-adder with sum (bit 0) and carry (bit 1) uses `'0'`..`'3'`.
11
+ *
12
+ * Components with internal carry chains (e.g. 8-bit ripple adder) use an
13
+ * **interleaved** encoding `CiSi` where sum occupies even bits (`2*i`) and
14
+ * carry occupies odd bits (`2*i + 1`). This stores intermediate carries for
15
+ * ripple animation, giving `outputCount = 2 * stageCount` (e.g. 16 bits /
16
+ * 4 hex digits for 8 stages, states `'0000'`..`'ffff'`).
17
+ *
18
+ * Transient (in-flight) states follow the `to${nextState}` convention so
19
+ * animations can be driven generically from `state`/`nextState`. The
20
+ * previously-held stable state is preserved in `parameters.prevState` so the
21
+ * behavior's `allowConductivity` keeps the old outputs energized until the
22
+ * transition fires.
23
+ *
24
+ * A special `'indeterminate'` state is used when any logic input is ill-defined.
25
+ *
26
+ * @public
27
+ */
28
+ export declare abstract class ArithmeticState extends ComponentState {
29
+ /**
30
+ * Number of logic outputs for this state
31
+ * (e.g. 2 for half/full adder, 9 for an 8-bit adder: 8 sum bits + carry out).
32
+ */
33
+ readonly outputCount: number;
34
+ /** Number of hex digits needed to encode all outputs. */
35
+ readonly hexDigitCount: number;
36
+ /** All-outputs-low state string (e.g. `'0'` for 2 outputs, `'000'` for 9). */
37
+ readonly allLowState: string;
38
+ protected constructor(componentId: UUID, outputCount: number, initialState: string);
39
+ /** True when the current state is a transient `to${stable}` transition. */
40
+ get isInTransition(): boolean;
41
+ /**
42
+ * Stable state that effectively drives the outputs right now:
43
+ * - stable state → returns that state
44
+ * - transient `to<hex>` → returns the previous stable kept in parameters
45
+ * - `'indeterminate'` → returns `'indeterminate'`
46
+ */
47
+ get effectiveState(): string;
48
+ /**
49
+ * Whether the `index`-th output is high in the current effective state.
50
+ * Returns `false` when effective state is `'indeterminate'`.
51
+ */
52
+ isOutputHigh(index: number): boolean;
53
+ }
@@ -0,0 +1,25 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { ArithmeticState } from './ArithmeticState';
3
+ /**
4
+ * Simulation state for the 8-bit ripple carry adder.
5
+ *
6
+ * Uses an interleaved 16-bit encoding `C7S7 C6S6 … C1S1 C0S0` where each
7
+ * stage occupies two bits: sum at even position (`2*i`) and carry at odd
8
+ * position (`2*i + 1`). This stores intermediate carries so the ripple
9
+ * animation can show carry propagation stage by stage.
10
+ *
11
+ * Stable states range from `'0000'` (all low) to `'ffff'` (all high).
12
+ * The external outputs are `sum-0`..`sum-7` (bits 0,2,4,…,14) and
13
+ * `carryOut` (bit 15 = C7).
14
+ *
15
+ * @public
16
+ */
17
+ export declare class EightBitAdderState extends ArithmeticState {
18
+ constructor(componentId: UUID, initialState?: string);
19
+ /** Whether stage `i`'s sum output is high in the current effective state. */
20
+ isSumHigh(stageIndex: number): boolean;
21
+ /** Whether stage `i`'s internal carry is high in the current effective state. */
22
+ isStageCarryHigh(stageIndex: number): boolean;
23
+ /** Whether the final carry out (C7) is high — drives the `carryOut` pin. */
24
+ isCarryOutHigh(): boolean;
25
+ }
@@ -0,0 +1,18 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { ArithmeticState } from './ArithmeticState';
3
+ /**
4
+ * Simulation state for the 8-bit one's complement (8 parallel XOR gates).
5
+ *
6
+ * Uses a 9-bit encoding stored as a 3-digit hex string (`'000'`..`'1ff'`):
7
+ * - Bits 0–7: output values (`output-i = input-i XOR invert`)
8
+ * - Bit 8: current invert input value (stored for animation)
9
+ *
10
+ * @public
11
+ */
12
+ export declare class EightBitOnesComplementState extends ArithmeticState {
13
+ constructor(componentId: UUID, initialState?: string);
14
+ /** Whether output bit `index` (0–7) is high in the current effective state. */
15
+ isOutputBitHigh(index: number): boolean;
16
+ /** Whether the invert flag (bit 8) is high in the current effective state. */
17
+ isInvertHigh(): boolean;
18
+ }
@@ -0,0 +1,16 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { ArithmeticState } from './ArithmeticState';
3
+ /**
4
+ * Simulation state for Half Adder components.
5
+ *
6
+ * Hex-encoded stable states: `'0'` (both low), `'1'` (sum high),
7
+ * `'2'` (carry high). `'3'` is unreachable because `sum = A XOR B`
8
+ * and `carry = A AND B` can never both be true.
9
+ *
10
+ * @public
11
+ */
12
+ export declare class HalfAdderState extends ArithmeticState {
13
+ constructor(componentId: UUID, initialState?: string);
14
+ get sumHigh(): boolean;
15
+ get carryHigh(): boolean;
16
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Arithmetic components simulation states
3
+ * @module core/simulation/states
4
+ */
5
+ export { ArithmeticState } from './ArithmeticState';
6
+ export { HalfAdderState } from './HalfAdderState';
7
+ export { AdderState } from './AdderState';
@@ -24,3 +24,18 @@ export { Nor8GateState } from './gates/Nor8GateState';
24
24
  export { XorGateState } from './gates/XorGateState';
25
25
  export { Xor4GateState } from './gates/Xor4GateState';
26
26
  export { Xor8GateState } from './gates/Xor8GateState';
27
+ export { ArithmeticState } from './arithmetic/ArithmeticState';
28
+ export { HalfAdderState } from './arithmetic/HalfAdderState';
29
+ export { AdderState } from './arithmetic/AdderState';
30
+ export { EightBitAdderState } from './arithmetic/EightBitAdderState';
31
+ export { EightBitOnesComplementState } from './arithmetic/EightBitOnesComplementState';
32
+ export { InputState } from './interface/InputState';
33
+ export { OneInputState } from './interface/OneInputState';
34
+ export { TwoInputState } from './interface/TwoInputState';
35
+ export { FourInputState } from './interface/FourInputState';
36
+ export { EightInputState } from './interface/EightInputState';
37
+ export { LightState } from './interface/LightState';
38
+ export { OneLightState } from './interface/OneLightState';
39
+ export { TwoLightState } from './interface/TwoLightState';
40
+ export { FourLightState } from './interface/FourLightState';
41
+ export { EightLightState } from './interface/EightLightState';
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { InputState } from './InputState';
3
+ /** Eight-switch user input. Stable states `'00'`..`'ff'`. */
4
+ export declare class EightInputState extends InputState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { LightState } from './LightState';
3
+ /** Eight-light input mirror. Stable states `'00'`–`'ff'`. */
4
+ export declare class EightLightState extends LightState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { InputState } from './InputState';
3
+ /** Four-switch user input. Stable states `'0'`..`'f'`. */
4
+ export declare class FourInputState extends InputState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { LightState } from './LightState';
3
+ /** Four-light input mirror. Stable states `'0'`–`'f'`. */
4
+ export declare class FourLightState extends LightState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -0,0 +1,45 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { ComponentState } from '../ComponentState';
3
+ /**
4
+ * Base simulation state for user-controlled input components (OneInput,
5
+ * TwoInput, FourInput, EightInput).
6
+ *
7
+ * Stable states are encoded as a zero-padded hexadecimal string where each
8
+ * bit position maps to one logic output (bit `i` ↔ `output-i`).
9
+ *
10
+ * While at least one switch is moving, the state value is the literal
11
+ * `'moving'` and the `parameters` map carries:
12
+ * - `prevState`: the stable hex value the outputs are still energizing
13
+ * - one entry per pending switch keyed by its index, encoded as
14
+ * `${target}-${startTick}-${endTick}` (target ∈ {0,1}).
15
+ *
16
+ * @public
17
+ */
18
+ export declare abstract class InputState extends ComponentState {
19
+ /** Number of logic outputs (1, 2, 4 or 8). */
20
+ readonly outputCount: number;
21
+ /** Number of hex digits needed to encode all outputs. */
22
+ readonly hexDigitCount: number;
23
+ /** All-outputs-low state string (e.g. `'0'` for 1–4 outputs, `'00'` for 8). */
24
+ readonly allLowState: string;
25
+ protected constructor(componentId: UUID, outputCount: number, initialState: string);
26
+ /** True while at least one switch is mid-transition. */
27
+ get isInTransition(): boolean;
28
+ /**
29
+ * Stable state that effectively drives the outputs right now:
30
+ * - stable state → returns that state
31
+ * - `'moving'` → returns the previous stable kept in `parameters.prevState`
32
+ */
33
+ get effectiveState(): string;
34
+ /** Whether output `index` is high in the current effective state. */
35
+ isOutputHigh(index: number): boolean;
36
+ /**
37
+ * Pending move descriptor for switch `index`, parsed from the parameter map,
38
+ * or `null` when no transition is in flight for that switch.
39
+ */
40
+ getPendingMove(index: number): {
41
+ target: 0 | 1;
42
+ startTick: number;
43
+ endTick: number;
44
+ } | null;
45
+ }
@@ -0,0 +1,54 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { ComponentState } from '../ComponentState';
3
+ /**
4
+ * Base simulation state for input-driven multi-light components (OneLight,
5
+ * TwoLight, FourLight, EightLight).
6
+ *
7
+ * Stable states are encoded as a zero-padded hexadecimal string where each
8
+ * bit position maps to one logic output (bit `i` ↔ `output-i`). Outputs
9
+ * mirror their corresponding `input-i` after `transitionSpan` ticks so the
10
+ * component can be cascaded.
11
+ *
12
+ * While at least one light is moving, the state value is the literal
13
+ * `'moving'` and the `parameters` map carries:
14
+ * - `prevState`: the stable hex value the outputs are still energizing
15
+ * - one entry per pending light keyed by its index, encoded as
16
+ * `${target}-${startTick}-${endTick}` (target ∈ {0,1}).
17
+ *
18
+ * A special `'indeterminate'` state is used when any logic input is
19
+ * ill-defined (set immediately by the non-logic-input guard).
20
+ *
21
+ * @public
22
+ */
23
+ export declare abstract class LightState extends ComponentState {
24
+ /** Number of lights / logic outputs (1, 2, 4 or 8). */
25
+ readonly lightCount: number;
26
+ /** Number of hex digits needed to encode all outputs. */
27
+ readonly hexDigitCount: number;
28
+ /** All-outputs-low state string (e.g. `'0'` for 1–4 lights, `'00'` for 8). */
29
+ readonly allLowState: string;
30
+ protected constructor(componentId: UUID, lightCount: number, initialState: string);
31
+ /** True while at least one light is mid-transition. */
32
+ get isInTransition(): boolean;
33
+ /**
34
+ * Stable state that effectively drives the outputs right now:
35
+ * - stable hex state → returns that state
36
+ * - `'moving'` → returns the previous stable kept in `parameters.prevState`
37
+ * - `'indeterminate'` → returns `'indeterminate'`
38
+ */
39
+ get effectiveState(): string;
40
+ /**
41
+ * Whether output `index` is high in the current effective state.
42
+ * Returns `false` when effective state is `'indeterminate'`.
43
+ */
44
+ isOutputHigh(index: number): boolean;
45
+ /**
46
+ * Pending move descriptor for light `index`, parsed from the parameter map,
47
+ * or `null` when no transition is in flight for that light.
48
+ */
49
+ getPendingMove(index: number): {
50
+ target: 0 | 1;
51
+ startTick: number;
52
+ endTick: number;
53
+ } | null;
54
+ }
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { InputState } from './InputState';
3
+ /** Single-switch user input. Stable states `'0'` and `'1'`. */
4
+ export declare class OneInputState extends InputState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { LightState } from './LightState';
3
+ /** Single-light input mirror. Stable states `'0'` and `'1'`. */
4
+ export declare class OneLightState extends LightState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { InputState } from './InputState';
3
+ /** Two-switch user input. Stable states `'0'`..`'3'`. */
4
+ export declare class TwoInputState extends InputState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -0,0 +1,6 @@
1
+ import { UUID } from '../../../utils/types';
2
+ import { LightState } from './LightState';
3
+ /** Two-light input mirror. Stable states `'0'`–`'3'`. */
4
+ export declare class TwoLightState extends LightState {
5
+ constructor(componentId: UUID, initialState?: string);
6
+ }
@@ -11,7 +11,7 @@ export declare const SIMULATION_SPEED: {
11
11
  /**
12
12
  * Maximum simulation speed in ticks per second
13
13
  */
14
- readonly MAX_TPS: 50;
14
+ readonly MAX_TPS: 100;
15
15
  /**
16
16
  * Default simulation speed in ticks per second
17
17
  */
@@ -44,8 +44,13 @@ export declare const TRANSITION_DEFAULTS: {
44
44
  export interface IUserCommand {
45
45
  /**
46
46
  * Type of command.
47
+ *
48
+ * - `toggle_switch`: flip a (double-throw) switch component.
49
+ * - `toggle_input`: flip one switch of a multi-switch input component
50
+ * (OneInput, TwoInput, FourInput, EightInput); `parameters` MUST carry
51
+ * `index` identifying which switch was toggled.
47
52
  */
48
- readonly type: 'toggle_switch';
53
+ readonly type: 'toggle_switch' | 'toggle_input';
49
54
  /**
50
55
  * UUID of target component.
51
56
  */
@@ -61,6 +66,9 @@ export interface IUserCommand {
61
66
  * - `tickCount`: Number of ticks for the switch transition. Computed at toggle time
62
67
  * using the formula: `ceil(transitionUserSpan × simulationSpeed / 1000)` with minimum of 1.
63
68
  * If not provided, behavior uses default transition timing.
69
+ *
70
+ * For `toggle_input` commands:
71
+ * - `index`: index of the toggled switch within the multi-switch component.
64
72
  */
65
73
  readonly parameters?: Map<string, string> | null;
66
74
  }
@@ -1,5 +1,5 @@
1
1
  import { UUID, Position, Rotation } from '../utils';
2
- import { ComponentType, IComponent } from './types';
2
+ import { ComponentType, IComponent, IPinMetadata } from './types';
3
3
  /**
4
4
  * Electrical component placed on the circuit grid.
5
5
  *
@@ -96,6 +96,11 @@ export declare class Component {
96
96
  */
97
97
  constructor(type: ComponentType, position: Position, rotation: Rotation, pins: ReadonlyArray<UUID>, editable?: boolean);
98
98
  getPinLabel(pinId: UUID): string | undefined;
99
+ getPinMetadata(pinId: UUID): IPinMetadata | undefined;
100
+ /** Resolve the ENode UUID of the logic pin at `index` within `interfaceName`, or undefined. */
101
+ getPinIdByInterface(interfaceName: string, index: number): UUID | undefined;
102
+ /** Largest index found across pins of the given logic interface, or -1 if none. */
103
+ getInterfaceMaxIndex(interfaceName: string): number;
99
104
  setAllParameters(config: Map<string, string>): void;
100
105
  setParameter(key: string, value: string): void;
101
106
  /**
@@ -1,5 +1,5 @@
1
1
  import { UUID, Position } from '../utils';
2
- import { ENodeSourceType, ENodeType, IENode } from './types';
2
+ import { ENodeSourceType, ENodeType, IENode, ILogicPinMetadata } from './types';
3
3
  import { Circuit } from './Circuit';
4
4
  /**
5
5
  * Electrical connection point (component pin or wire branching point).
@@ -76,6 +76,10 @@ export declare class ENode {
76
76
  * @readonly
77
77
  */
78
78
  readonly subtype: string;
79
+ /**
80
+ * logic pin metadata for logicInput / logicOutput pins
81
+ */
82
+ readonly logicMetadata: ILogicPinMetadata | undefined;
79
83
  /**
80
84
  * Create a new electrical node.
81
85
  *
@@ -89,6 +93,7 @@ export declare class ENode {
89
93
  * @param source - Source type (Voltage/Current) or undefined
90
94
  *
91
95
  * @param subtype
96
+ * @param logicMetadata
92
97
  * @example
93
98
  * ```typescript
94
99
  * // Pin node (internal to Circuit)
@@ -110,7 +115,7 @@ export declare class ENode {
110
115
  * );
111
116
  * ```
112
117
  */
113
- constructor(type: ENodeType, component: UUID | undefined, pinLabel: string | undefined, position: Position | undefined, source?: ENodeSourceType | undefined, subtype?: string);
118
+ constructor(type: ENodeType, component: UUID | undefined, pinLabel: string | undefined, position: Position | undefined, source: ENodeSourceType | undefined, subtype: string | undefined, logicMetadata: ILogicPinMetadata | undefined);
114
119
  /**
115
120
  * Get the position of this electrical node.
116
121
  *
@@ -12,3 +12,5 @@ export { CircuitOptions } from './CircuitOptions.js';
12
12
  export { CircuitMetadata } from './CircuitMetadata.js';
13
13
  export { Circuit } from './Circuit.js';
14
14
  export { computeTransitionSpan, classifyGate, computeGateDelay } from './delays.js';
15
+ export { findPinsReachableFromBp, findBpsAtLogicDistance, findPinsReachableFromBpWithPath, findBpsAtLogicDistanceWithPath, } from './networkTraversal.js';
16
+ export type { IPinReach, IBpAtDistance } from './networkTraversal.js';
@@ -0,0 +1,50 @@
1
+ import { Circuit } from './Circuit';
2
+ import { UUID } from '../utils';
3
+ /** Reach record returned by `findPinsReachableFromBpWithPath`. */
4
+ export interface IPinReach {
5
+ /** Logic distance — number of wire edges from the start BP to this pin. */
6
+ Dl: number;
7
+ /** ENode immediately preceding the pin on the shortest BFS path back to the
8
+ * start BP. For Dl=1 this is the start BP itself. */
9
+ predecessor: UUID;
10
+ }
11
+ /** Sibling record returned by `findBpsAtLogicDistanceWithPath`. */
12
+ export interface IBpAtDistance {
13
+ /** Branching-point UUID at exactly the requested logic distance. */
14
+ id: UUID;
15
+ /** ENode immediately preceding this BP on the shortest BFS path back to
16
+ * the start pin. For Dl=1 this is the start pin itself. */
17
+ predecessor: UUID;
18
+ }
19
+ /** BFS the BP-only sub-graph from a start branching point and report every
20
+ * pin reached as a terminal endpoint, with its logic distance Dl.
21
+ *
22
+ * Pins are NEVER traversed through. If two paths reach the same pin, the
23
+ * smallest Dl wins.
24
+ *
25
+ * @returns A map of `pinId → Dl`. Empty if no pin is reachable.
26
+ */
27
+ export declare function findPinsReachableFromBp(circuit: Circuit, startBpId: UUID): Map<UUID, number>;
28
+ /** Same as `findPinsReachableFromBp` but each entry also carries the BFS
29
+ * predecessor (the ENode one step closer to the start BP on the shortest
30
+ * path). Used by rule 4 to identify which of newBP's two wires leads back
31
+ * to the anchor pin.
32
+ *
33
+ * Map insertion order matches BFS visit order, so iterating it yields ties
34
+ * in BFS-first order.
35
+ */
36
+ export declare function findPinsReachableFromBpWithPath(circuit: Circuit, startBpId: UUID): Map<UUID, IPinReach>;
37
+ /** BFS the BP-only sub-graph from a start pin and return every BP reached at
38
+ * exactly logic distance `Dl` (i.e. path-edge count = `Dl`).
39
+ *
40
+ * Branches that hit any pin before reaching the target depth are cut. The
41
+ * start pin itself is never returned.
42
+ *
43
+ * @returns Array of branching-point UUIDs at logic distance Dl from the pin.
44
+ */
45
+ export declare function findBpsAtLogicDistance(circuit: Circuit, startPinId: UUID, Dl: number): UUID[];
46
+ /** Same as `findBpsAtLogicDistance` but each entry carries the BFS
47
+ * predecessor (one step closer to the start pin). Used by rule 4 to identify
48
+ * which wire of each sibling to split.
49
+ */
50
+ export declare function findBpsAtLogicDistanceWithPath(circuit: Circuit, startPinId: UUID, Dl: number): IBpAtDistance[];