simple-circuit-engine 0.0.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CircuitRunner-CAeE31M5.js","sources":["../src/core/types/Position3D.ts","../src/core/types/CameraOptions.ts","../src/core/types/ENodeSourceType.ts","../src/core/types/ComponentType.ts","../src/core/types/ENodeType.ts","../src/core/types/Identifier.ts","../src/core/types/Position.ts","../src/core/types/Rotation.ts","../src/core/Component.ts","../src/core/simulation/SimulationState.ts","../src/core/simulation/StateManager.ts","../src/core/simulation/EventQueue.ts","../src/core/simulation/DirtyTracker.ts","../src/core/simulation/types/SimulationConstants.ts","../src/core/simulation/CircuitRunner.ts"],"sourcesContent":["/**\n * 3D Position Type\n *\n * Represents a 3D position. Used for:\n * - Camera placement\n *\n * @module core/types/Position3D\n */\n\nexport type IPosition3D = {\n x: number;\n y: number;\n z: number;\n};\n\n/**\n * 3D position.\n * Positions are immutable once created.\n *\n * @example\n * ```typescript\n * const pos3 = new Position3D(10, 20, 40);\n * console.log(pos.x); // 10\n * console.log(pos.y); // 20\n * console.log(pos.y); // 40\n *\n * ```\n */\nexport class Position3D {\n /**\n * Create a new 3D position.\n *\n * @param x - X coordinate\n * @param y - Y coordinate\n * @param z - Z coordinate\n */\n constructor(\n public readonly x: number,\n public readonly y: number,\n public readonly z: number\n ) {}\n\n /**\n * Check if this position equals another position.\n *\n * @param other - Position to compare with\n * @returns true if x,y and z coordinates are equal\n *\n * @example\n * ```typescript\n * const p1 = new Position(10, 20, 40);\n * const p2 = new Position(10, 20, 40);\n * const p3 = new Position(15, 20, 40);\n *\n * console.log(p1.equals(p2)); // true\n * console.log(p1.equals(p3)); // false\n * ```\n */\n equals(other: Position3D): boolean {\n return this.x === other.x && this.y === other.y && this.z === other.z;\n }\n\n /**\n * Serialize position to JSON.\n *\n * @returns Plain object with x, y and z properties\n *\n * @example\n * ```typescript\n * const pos = new Position(10, 20, 40);\n * const json = pos.toJSON();\n * console.log(json); // { x: 10, y: 20, z: 40 }\n * ```\n */\n toJSON(): IPosition3D {\n return { x: this.x, y: this.y, z: this.z };\n }\n\n /**\n * Deserialize position from JSON.\n *\n * @param json - Plain object with x, y and z properties\n * @returns Position instance\n *\n * @example\n * ```typescript\n * const json = { x: 10, y: 20, z: 40 };\n * const pos = Position.fromJSON(json);\n * console.log(pos.x); // 10\n * ```\n */\n static fromJSON(json: IPosition3D): Position3D {\n return new Position3D(json.x, json.y, json.z);\n }\n\n /**\n * String representation for debugging.\n *\n * @returns String in format \"Position(x, y, z)\"\n */\n toString(): string {\n return `Position(${this.x}, ${this.y}, ${this.z})`;\n }\n}\n","/**\n * Camera Options Type\n *\n * Represents camera configuration options for the 3D scene.\n *\n * @module core/types/CameraOptions\n */\n\nimport { type IPosition3D, Position3D } from './Position3D';\n\nexport type ICameraOptions = {\n position: IPosition3D;\n lookAtPosition: IPosition3D;\n fov: number;\n near: number;\n far: number;\n};\n\n/**\n * Camera configuration options.\n *\n * @example\n * ```typescript\n * // Create with defaults\n * const defaultOpts = new CameraOptions();\n *\n * // Create with custom values\n * const customOpts = new CameraOptions(\n * new Position3D(0, 20, 10),\n * new Position3D(5, 0, 0),\n * 60,\n * 0.5,\n * 2000\n * );\n * ```\n */\nexport class CameraOptions {\n /**\n * Create new camera options.\n *\n * @param position - Camera position (default: 0, 15, 15)\n * @param lookAtPosition - Camera look-at target position (default: 0, 0, 0)\n * @param fov - Field of view in degrees (default: 75)\n * @param near - Near clipping plane distance (default: 0.1)\n * @param far - Far clipping plane distance (default: 1000)\n */\n constructor(\n public readonly position: Position3D = new Position3D(0, 15, 15),\n public readonly lookAtPosition: Position3D = new Position3D(0, 0, 0),\n public readonly fov: number = 75,\n public readonly near: number = 0.1,\n public readonly far: number = 1000\n ) {}\n\n /**\n * Serialize camera options to JSON.\n *\n * @returns Plain object with camera configuration\n *\n * @example\n * ```typescript\n * const opts = new CameraOptions();\n * const json = opts.toJSON();\n * console.log(json);\n * // {\n * // position: { x: 0, y: 15, z: 0 },\n * // lookAtPosition: { x: 0, y: 0, z: 0 },\n * // fov: 75,\n * // near: 0.1,\n * // far: 1000\n * // }\n * ```\n */\n toJSON(): ICameraOptions {\n return {\n position: this.position.toJSON(),\n lookAtPosition: this.lookAtPosition.toJSON(),\n fov: this.fov,\n near: this.near,\n far: this.far,\n };\n }\n\n /**\n * Deserialize camera options from JSON.\n *\n * @param json - Plain object with camera configuration\n * @returns CameraOptions instance\n *\n * @example\n * ```typescript\n * const json = {\n * position: { x: 0, y: 20, z: 10 },\n * lookAtPosition: { x: 5, y: 0, z: 0 },\n * fov: 60,\n * near: 0.5,\n * far: 2000\n * };\n * const opts = CameraOptions.fromJSON(json);\n * console.log(opts.position.y); // 20\n * ```\n */\n static fromJSON(json: ICameraOptions): CameraOptions {\n return new CameraOptions(\n Position3D.fromJSON(json.position),\n Position3D.fromJSON(json.lookAtPosition),\n json.fov,\n json.near,\n json.far\n );\n }\n\n /**\n * String representation for debugging.\n *\n * @returns String with camera configuration details\n */\n toString(): string {\n return `CameraOptions(position: ${this.position.toString()}, lookAt: ${this.lookAtPosition.toString()}, fov: ${this.fov}, near: ${this.near}, far: ${this.far})`;\n }\n}\n","/**\n * ENode Source Type Enumeration\n *\n * Defines the two types of electrical pinSources in the circuit model.\n *\n * @module core/types/ENodeSourceType\n */\n\n/**\n * Type of electrical pinSources in the circuit.\n *\n * ENodes have a sourceType which can be undefined or one of the following:\n *\n * - **Voltage**: ENode that provides a voltage source to the circuit. All Enodes of this type are considered at the same positive potential.\n *\n * - **Current**: Ground/neutral ENodes that provides a current source to the circuit. All Enodes of this type are considered as points at\n * the same 0V potential and are points from where electrons enters the circuit.\n *\n * playback modules use these properties to determine where to draw voltage/current from.\n *\n */\nexport enum ENodeSourceType {\n /**\n * Voltage pinSources\n */\n Voltage = 'Voltage',\n\n /**\n * Current pinSources\n */\n Current = 'Current',\n}\n","/**\n * Component Type Definitions\n *\n * Defines the available component types with their metadata including\n * unique identifiers, display names, and pin counts.\n *\n * @module core/types/ComponentType\n */\n\nimport { ENodeSourceType } from './ENodeSourceType';\n\n/**\n * Enumeration of available component types.\n *\n * Each component type represents a specific electrical element that can be\n * placed in a circuit (battery, LED, transistor, etc.).\n *\n * @example\n * ```typescript\n * const type = ComponentType.Battery;\n * const metadata = COMPONENT_TYPE_METADATA[type];\n * console.log(metadata.name); // \"Battery\"\n * console.log(metadata.pins); // Map([[\"cathode\", ENodeSourceType.Voltage], [\"anode\", ENodeSourceType.Current]])\n * ```\n */\nexport enum ComponentType {\n Battery = 'battery',\n Switch = 'switch',\n Lightbulb = 'lightbulb',\n Relay = 'relay',\n Transistor = 'transistor',\n SmallLED = 'smallLED',\n RectangleLED = 'rectangleLED',\n Cube = 'cube', // no pins component for testing purposes mainly\n Label = 'label', // decorative text label with no pins\n}\n\n/**\n * Metadata for a component type.\n *\n * @property id - Unique string identifier matching the enum value\n * @property name - Human-readable display name\n * @property pins - Array of pin labels (order-significant)\n * @property config - Default configuration parameters (depends on the component, e.g., initialState, activationLogic, color...)\n */\nexport interface ComponentTypeMetadata {\n readonly id: string;\n readonly name: string;\n readonly pins: Map<string, ENodeSourceType | undefined>;\n readonly config: Map<string, string>;\n}\n\n/**\n * Component type metadata lookup table.\n *\n * Maps each ComponentType enum value to its associated metadata\n * (id, display name, pins, and default configuration arguments).\n *\n * @example\n * ```typescript\n * const metadata = COMPONENT_TYPE_METADATA[ComponentType.Battery];\n * console.log(metadata);\n * // {\n * // id: 'battery',\n * // name: 'Battery',\n * // pins: ['cathode', 'anode'],\n * // config: Map { 'voltage' => '9', 'unit' => 'V' }\n * // }\n *\n * // Access component type default configuration\n * const voltage = metadata.config.get('voltage'); // '9'\n * ```\n */\nexport const COMPONENT_TYPE_METADATA: Readonly<Record<ComponentType, ComponentTypeMetadata>> = {\n [ComponentType.Switch]: {\n id: ComponentType.Switch,\n name: 'Switch',\n pins: new Map([\n ['input', undefined],\n ['output', undefined],\n ]),\n config: new Map([\n ['initialState', 'open'],\n ['size', '1'],\n ]),\n },\n [ComponentType.Battery]: {\n id: ComponentType.Battery,\n name: 'Battery',\n pins: new Map([\n ['cathode', ENodeSourceType.Voltage],\n ['anode', ENodeSourceType.Current],\n ]),\n config: new Map([]),\n },\n [ComponentType.Lightbulb]: {\n id: ComponentType.Lightbulb,\n name: 'Lightbulb',\n pins: new Map([\n ['pin1', undefined],\n ['pin2', undefined],\n ]),\n config: new Map([['size', '1']]),\n },\n [ComponentType.Relay]: {\n id: ComponentType.Relay,\n name: 'Relay',\n pins: new Map([\n ['cmd_in', undefined],\n ['cmd_out', undefined],\n ['power_in', undefined],\n ['power_out', undefined],\n ]),\n config: new Map([\n ['activationLogic', 'positive'],\n ['initializationOrder', ''],\n ]),\n },\n [ComponentType.Transistor]: {\n id: ComponentType.Transistor,\n name: 'Transistor',\n pins: new Map([\n ['collector', undefined],\n ['base', undefined],\n ['emitter', undefined],\n ]),\n config: new Map([\n ['activationLogic', 'positive'],\n ['initializationOrder', ''],\n ]),\n },\n [ComponentType.SmallLED]: {\n id: ComponentType.SmallLED,\n name: 'SmallLED',\n pins: new Map([\n ['cathode', undefined],\n ['anode', undefined],\n ]),\n config: new Map([\n ['mode', 'symmetric'],\n ['idleColor', 'white'],\n ['activeColor', '#ffff00'],\n ['size', '1'],\n ['ywRatio', '1'],\n ]),\n },\n [ComponentType.RectangleLED]: {\n id: ComponentType.RectangleLED,\n name: 'RectangleLED',\n pins: new Map([\n ['cathode', undefined],\n ['anode', undefined],\n ]),\n config: new Map([\n ['mode', 'symmetric'],\n ['idleColor', 'white'],\n ['activeColor', '#ffff00'],\n ['size', '1'],\n ['hwRatio', '1'],\n ['ywRatio', '1'],\n ]),\n },\n [ComponentType.Cube]: {\n id: ComponentType.Cube,\n name: 'Cube',\n pins: new Map([]),\n config: new Map([['color', 'red']]),\n },\n [ComponentType.Label]: {\n id: ComponentType.Label,\n name: 'Label',\n pins: new Map([]),\n config: new Map([\n ['text', 'Label'],\n ['size', '1'],\n ]),\n },\n};\n\n/**\n * Get all available component types.\n *\n * @returns Array of all ComponentType enum values\n *\n * @example\n * ```typescript\n * const types = getAllComponentTypes();\n * console.log(types); // [ComponentType.Resistor, ComponentType.Capacitor, ...]\n * ```\n */\nexport function getAllComponentTypes(): ComponentType[] {\n return Object.values(ComponentType);\n}\n\n/**\n * Get metadata for a specific component type.\n *\n * @param type - The component type\n * @returns Component metadata (id, name, pinCount)\n *\n * @example\n * ```typescript\n * const metadata = getComponentTypeMetadata(ComponentType.Transistor);\n * console.log(metadata.pinCount); // 3\n * ```\n */\nexport function getComponentTypeMetadata(type: ComponentType): ComponentTypeMetadata {\n return COMPONENT_TYPE_METADATA[type];\n}\n","/**\n * ENode Type Enumeration\n *\n * Defines the two types of electrical connection points in the circuit model.\n *\n * @module core/types/ENodeType\n */\n\n/**\n * Type of electrical node (ENode) in the circuit.\n *\n * ENodes represent atomic electrical connection points and come in two variants (immutable after node creation):\n *\n * - **Pin**: Connection point belonging to a Component. Position is derived\n * from the parent component's position, rotation, and pin index. Automatically\n * created when a component is added, deleted when component is removed.\n *\n * - **BranchingPoint**: Junction point where wires split. Has an independent\n * position on the grid. Automatically created when wires are split, deleted\n * when no wires remain connected (orphaned).\n *\n * @example\n * ```typescript\n * // Pin node (belongs to component)\n * if (node.type === ENodeType.Pin) {\n * console.log('Component pin with label', node.pinLabel);\n * }\n *\n * // Branching point (wire junction)\n * if (node.type === ENodeType.BranchingPoint) {\n * console.log('Branch at position', node.position);\n * }\n * ```\n */\nexport enum ENodeType {\n /**\n * Component pin connection point.\n *\n * Properties:\n * - Has parent component reference\n * - Has pin label within component\n * - Position derived from component\n * - Lifecycle tied to component (cascade deletion)\n */\n Pin = 'Pin',\n\n /**\n * Wire branching point (junction).\n *\n * Properties:\n * - Independent position on grid\n * - Created when wire is split\n * - Deleted when last wire is removed (orphaned cleanup)\n * - No parent component\n */\n BranchingPoint = 'BranchingPoint',\n}\n","/**\n * UUID Type and Generation Utilities\n *\n * Provides RFC 4122 UUID v4 identifiers for all entities in the circuit model.\n * Uses native crypto.randomUUID() when available (modern browsers, Node 19+),\n * with fallback for older environments.\n *\n * @module core/types/Identifier\n */\n\n/**\n * Universally Unique Identifier (RFC 4122 UUID v4).\n *\n * Used as the primary identifier for all circuit entities:\n * - Circuit\n * - Component\n * - ENode (electrical nodes)\n * - Wire\n *\n * @example\n * ```typescript\n * const id: UUID = generateUUID();\n * console.log(id); // \"550e8400-e29b-41d4-a716-446655440000\"\n * ```\n */\nexport type UUID = string;\n\n/**\n * Generate a new RFC 4122 UUID v4 identifier.\n *\n * Uses the native `crypto.randomUUID()` API when available (ES2022+ browsers,\n * Node 19+). For older Node.js environments in testing, falls back to a\n * polyfill implementation.\n *\n * @returns A newly generated UUID string\n *\n * @example\n * ```typescript\n * const componentId = generateUUID();\n * const wireId = generateUUID();\n * console.log(componentId !== wireId); // true (collision probability: ~10^-36)\n * ```\n */\nexport function generateUUID(): UUID {\n // Native crypto API (modern browsers and Node 19+)\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback for older Node.js (testing environments)\n // Simple UUID v4 implementation without external dependencies\n // Based on RFC 4122 specification\n const hexDigits = '0123456789abcdef';\n const sections = [8, 4, 4, 4, 12];\n const parts: string[] = [];\n\n for (const length of sections) {\n let part = '';\n for (let i = 0; i < length; i++) {\n const randomByte = Math.floor(Math.random() * 16);\n part += hexDigits[randomByte];\n }\n parts.push(part);\n }\n\n // Set version (4) and variant (10) bits as per RFC 4122\n const uuid = parts.join('-');\n const chars = uuid.split('');\n\n // Set version 4 in the time_hi_and_version field\n chars[14] = '4';\n\n // Set variant (10xx in binary) in the clock_seq_hi_and_reserved field\n const variantChar = parseInt(chars[19] ?? '0', 16);\n const variantIndex = (variantChar & 0x3) | 0x8;\n chars[19] = hexDigits[variantIndex] ?? '0';\n\n return chars.join('');\n}\n","/**\n * Position Type for 2D Discrete Grid\n *\n * Represents a position on a 2D discrete (integer) grid. Used for:\n * - Component placement\n * - Branching point ENode positions\n * - Wire intermediate waypoints\n *\n * @module core/types/Position\n */\n\n/**\n * Position on a 2D discrete grid with integer coordinates.\n *\n * Enforces integer constraint at construction time to ensure all positions\n * align with the discrete grid model. Positions are immutable once created.\n *\n * @example\n * ```typescript\n * const pos = new Position(10, 20);\n * console.log(pos.x); // 10\n * console.log(pos.y); // 20\n *\n * // Invalid: non-integer coordinates\n * const invalid = new Position(10.5, 20); // TypeError\n * ```\n */\nexport class Position {\n /**\n * Create a new position on the discrete grid.\n *\n * @param x - X coordinate (must be integer)\n * @param y - Y coordinate (must be integer)\n * @throws {TypeError} If x or y are not integers\n */\n constructor(\n public readonly x: number,\n public readonly y: number\n ) {\n if (!Number.isInteger(x) || !Number.isInteger(y)) {\n throw new TypeError(`Position coordinates must be integers (got x=${x}, y=${y})`);\n }\n }\n\n /**\n * Check if this position equals another position.\n *\n * @param other - Position to compare with\n * @returns true if both x and y coordinates are equal\n *\n * @example\n * ```typescript\n * const p1 = new Position(10, 20);\n * const p2 = new Position(10, 20);\n * const p3 = new Position(15, 20);\n *\n * console.log(p1.equals(p2)); // true\n * console.log(p1.equals(p3)); // false\n * ```\n */\n equals(other: Position): boolean {\n return this.x === other.x && this.y === other.y;\n }\n\n /**\n * Serialize position to JSON.\n *\n * @returns Plain object with x and y properties\n *\n * @example\n * ```typescript\n * const pos = new Position(10, 20);\n * const json = pos.toJSON();\n * console.log(json); // { x: 10, y: 20 }\n * ```\n */\n toJSON(): { x: number; y: number } {\n return { x: this.x, y: this.y };\n }\n\n /**\n * Deserialize position from JSON.\n *\n * @param json - Plain object with x and y properties\n * @returns Position instance\n * @throws {TypeError} If coordinates are not integers\n *\n * @example\n * ```typescript\n * const json = { x: 10, y: 20 };\n * const pos = Position.fromJSON(json);\n * console.log(pos.x); // 10\n * ```\n */\n static fromJSON(json: { x: number; y: number }): Position {\n return new Position(json.x, json.y);\n }\n\n /**\n * String representation for debugging.\n *\n * @returns String in format \"Position(x, y)\"\n */\n toString(): string {\n return `Position(${this.x}, ${this.y})`;\n }\n}\n\n/**\n * Given a path defined by an array of 2D positions, find the best index to insert\n * a target position so that the path shape is preserved as much as possible.\n *\n * This is used when splitting a wire at a position: we need to determine which\n * segment of the path the target falls on, and return the insertion index.\n *\n * Algorithm:\n * 1. For each consecutive pair of positions (segment), calculate the perpendicular\n * distance from target to that segment\n * 2. Return the index after the start of the closest segment\n *\n * @param positions - Array of positions defining the path (typically includes\n * start endpoint, intermediate positions, and end endpoint)\n * @param target - Position to insert\n * @param minDistance - Optional maximum distance to consider (default: Infinity)\n * @returns Index where target should be inserted (0 to positions.length)\n *\n * @example\n * ```typescript\n * // Path: (0,0) -> (10,0) -> (10,10) -> (20,10)\n * const path = [\n * new Position(0, 0),\n * new Position(10, 0),\n * new Position(10, 10),\n * new Position(20, 10)\n * ];\n * // Target at (5, 0) - on first segment\n * findPositionBestIndex(path, new Position(5, 0)); // Returns 1\n * // Target at (10, 5) - on second segment\n * findPositionBestIndex(path, new Position(10, 5)); // Returns 2\n * ```\n */\nexport function findPositionBestIndex(\n positions: Position[],\n target: Position,\n minDistance = Infinity\n): number {\n // Edge case: empty array - insert at beginning\n if (positions.length === 0) {\n return 0;\n }\n\n // Edge case: single position - insert after it\n if (positions.length === 1) {\n return 1;\n }\n\n let bestIndex = 1; // Default: insert after first position\n\n // Iterate through all segments\n for (let i = 0; i < positions.length - 1; i++) {\n const segmentStart = positions[i]!;\n const segmentEnd = positions[i + 1]!;\n\n const distance = pointToSegmentDistance(target, segmentStart, segmentEnd);\n\n if (distance < minDistance) {\n minDistance = distance;\n bestIndex = i + 1; // Insert after the segment start\n }\n }\n\n return bestIndex;\n}\n\n/**\n * Calculate the shortest distance from a point to a line segment.\n *\n * @param point - The point to measure from\n * @param segmentStart - Start of the line segment\n * @param segmentEnd - End of the line segment\n * @returns The shortest distance from point to the segment\n */\nfunction pointToSegmentDistance(\n point: Position,\n segmentStart: Position,\n segmentEnd: Position\n): number {\n const dx = segmentEnd.x - segmentStart.x;\n const dy = segmentEnd.y - segmentStart.y;\n\n // If segment is a point, return distance to that point\n const segmentLengthSquared = dx * dx + dy * dy;\n if (segmentLengthSquared === 0) {\n return Math.sqrt((point.x - segmentStart.x) ** 2 + (point.y - segmentStart.y) ** 2);\n }\n\n // Calculate projection of point onto the line (as parameter t)\n // t = 0 means closest point is segmentStart, t = 1 means segmentEnd\n const t = Math.max(\n 0,\n Math.min(\n 1,\n ((point.x - segmentStart.x) * dx + (point.y - segmentStart.y) * dy) / segmentLengthSquared\n )\n );\n\n // Calculate closest point on segment\n const closestX = segmentStart.x + t * dx;\n const closestY = segmentStart.y + t * dy;\n\n // Return distance to closest point\n return Math.sqrt((point.x - closestX) ** 2 + (point.y - closestY) ** 2);\n}\n\n/**\n * Simplify a path by removing collinear intermediate positions.\n *\n * Given an ordered array of positions representing a line path, this function\n * removes positions that lie on the same line as their neighbors (collinear points).\n * The resulting path is visually identical but with fewer redundant points.\n *\n * Three points A, B, C are collinear if B lies on the line from A to C.\n * When collinear, B is redundant and can be removed without changing the path shape.\n *\n * @param positions - Ordered array of positions representing the path\n * @param tolerance - Optional tolerance for collinearity check (default: 5)\n * @returns Simplified array with collinear intermediate points removed\n *\n * @example\n * ```typescript\n * // Horizontal line with redundant middle points\n * const path = [\n * new Position(0, 0),\n * new Position(5, 0), // collinear - will be removed\n * new Position(10, 0), // collinear - will be removed\n * new Position(15, 0)\n * ];\n * simplifyPositions(path);\n * // Returns: [Position(0, 0), Position(15, 0)]\n *\n * // L-shaped path - corner point is NOT collinear\n * const lPath = [\n * new Position(0, 0),\n * new Position(10, 0), // corner - kept\n * new Position(10, 10)\n * ];\n * simplifyPositions(lPath);\n * // Returns: [Position(0, 0), Position(10, 0), Position(10, 10)]\n * ```\n */\nexport function simplifyPositions(positions: Position[], tolerance: number = 5): Position[] {\n // Edge cases: 0, 1, or 2 points can't be simplified\n if (positions.length <= 2) {\n return [...positions];\n }\n\n // Start with the first point\n const result: Position[] = [positions[0]!];\n\n // Check each intermediate point\n for (let i = 1; i < positions.length - 1; i++) {\n const prev = result[result.length - 1]!;\n const current = positions[i]!;\n const next = positions[i + 1]!;\n\n // Keep the point only if it's NOT collinear with prev and next\n if (!areCollinear(prev, current, next, tolerance)) {\n result.push(current);\n }\n // If collinear, skip current (it's redundant)\n }\n\n // Always add the last point\n result.push(positions[positions.length - 1]!);\n\n return result;\n}\n\n/**\n * Check if three points are collinear (lie on the same line).\n *\n * Uses the cross product of vectors AB and AC. If the cross product\n * is zero, the points are collinear.\n *\n * @param a - First point\n * @param b - Second point (middle)\n * @param c - Third point\n * @param tolerance - Optional tolerance for collinearity check (default: 5)\n * @returns true if the three points are collinear\n */\nfunction areCollinear(a: Position, b: Position, c: Position, tolerance: number = 5): boolean {\n // Cross product of vectors AB and AC\n // crossProduct = (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x)\n // If zero, points are collinear\n const crossProduct = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);\n return Math.abs(crossProduct) <= tolerance;\n}\n","/**\n * Rotation Type for Component Orientation\n *\n * Represents orientation angle for components on the 2D grid.\n * Uses integer degrees for discrete rotation values.\n *\n * @module core/types/Rotation\n */\n\n/**\n * Rotation angle for component orientation.\n *\n * Enforces integer constraint at construction time. Typically used with\n * values like 0, 90, 180, 270 degrees, but any integer is valid.\n * Rotations are immutable once created.\n *\n * @example\n * ```typescript\n * const rotation = new Rotation(90);\n * console.log(rotation.angle); // 90\n *\n * // Invalid: non-integer angle\n * const invalid = new Rotation(45.5); // TypeError\n * ```\n */\nexport class Rotation {\n /**\n * Create a new rotation with the specified angle.\n *\n * @param angle - Rotation angle in degrees (must be integer)\n * @throws {TypeError} If angle is not an integer\n */\n constructor(public readonly angle: number) {\n if (!Number.isInteger(angle)) {\n throw new TypeError(`Rotation angle must be an integer (got ${angle})`);\n }\n }\n\n /**\n * Serialize rotation to JSON.\n *\n * @returns The angle value as a number\n *\n * @example\n * ```typescript\n * const rotation = new Rotation(90);\n * const json = rotation.toJSON();\n * console.log(json); // 90\n * ```\n */\n toJSON(): number {\n return this.angle;\n }\n\n /**\n * Deserialize rotation from JSON.\n *\n * @param angle - Angle value\n * @returns Rotation instance\n * @throws {TypeError} If angle is not an integer\n *\n * @example\n * ```typescript\n * const rotation = Rotation.fromJSON(90);\n * console.log(rotation.angle); // 90\n * ```\n */\n static fromJSON(angle: number): Rotation {\n return new Rotation(angle);\n }\n\n /**\n * Check if this rotation equals another rotation.\n *\n * @param other - Rotation to compare with\n * @returns true if angles are equal\n *\n * @example\n * ```typescript\n * const r1 = new Rotation(90);\n * const r2 = new Rotation(90);\n * const r3 = new Rotation(180);\n *\n * console.log(r1.equals(r2)); // true\n * console.log(r1.equals(r3)); // false\n * ```\n */\n equals(other: Rotation): boolean {\n return this.angle === other.angle;\n }\n\n /**\n * String representation for debugging.\n *\n * @returns String in format \"Rotation(angle°)\"\n */\n toString(): string {\n return `Rotation(${this.angle}°)`;\n }\n}\n","/**\n * Component Class\n *\n * Base class for electrical components in the circuit.\n * Components have a position, rotation, and collection of pin ENodes.\n *\n * @module core/Component\n */\n\nimport type { UUID } from './types/Identifier.js';\nimport { generateUUID } from './types/Identifier.js';\nimport { Position } from './types/Position.js';\nimport { Rotation } from './types/Rotation.js';\nimport {\n COMPONENT_TYPE_METADATA,\n type ComponentType,\n getComponentTypeMetadata,\n} from './types/ComponentType.js';\n\n/**\n * Electrical component placed on the circuit grid.\n *\n * Components represent physical circuit elements (lightbulbs, transistors, etc.)\n * with a specific position, orientation, and set of electrical connection pins.\n *\n * **Lifecycle**: Components are created and removed via the Circuit class.\n * When a component is added to a circuit, pin ENodes are automatically created\n * for each pin. When removed, pins and connected wires are cascade-deleted.\n *\n * @example\n * ```typescript\n * const position = new Position(10, 20);\n * const rotation = new Rotation(90);\n * const pins = ['pin-uuid-1', 'pin-uuid-2'];\n *\n * const component = new Component(position, rotation, pins);\n *\n * console.log(component.id); // \"550e8400-...\"\n * console.log(component.position); // Position { x: 10, y: 20 }\n * console.log(component.rotation); // Rotation { angle: 90 }\n * console.log(component.pins); // ['pin-uuid-1', 'pin-uuid-2']\n * ```\n */\nexport class Component {\n /**\n * Unique identifier for this component.\n * @readonly\n */\n public readonly id: UUID;\n\n /**\n * Component type (Battery, Switch, LED, etc.).\n * @readonly\n */\n public readonly type: ComponentType;\n\n /**\n * Position on the 2D discrete grid.\n * @readonly\n */\n public readonly position: Position;\n\n /**\n * Orientation angle in degrees.\n * @readonly\n */\n public readonly rotation: Rotation;\n\n /**\n * Array of pin ENode UUIDs.\n * Pin order is significant (index 0 is first pin, etc.).\n * @readonly\n */\n public readonly pins: ReadonlyArray<UUID>;\n\n /**\n * Configuration parameters for this component instance.\n *\n * This map holds key-value pairs representing configurable settings\n * The available configuration keys depend on the component type see ComponentTypeMetadata for details.\n *\n */\n public config: Map<string, string>;\n\n /**\n * Create a new component.\n *\n * **Note**: Typically components are created via `Circuit.addComponent()`\n * which handles pin ENode creation automatically. This constructor is used\n * internally by Circuit.\n *\n * @param type - Component type (Battery, Switch, LED, etc.)\n * @param position - Grid position (integer x, y)\n * @param rotation - Orientation angle (integer degrees)\n * @param pins - Array of pin ENode UUIDs\n *\n * @example\n * ```typescript\n * // Usually created via Circuit:\n * const component = circuit.addComponent(\n * new Position(10, 20),\n * new Rotation(90),\n * ComponentType.Battery\n * );\n *\n * // Direct construction (for deserialization):\n * const component = new Component(\n * ComponentType.Battery,\n * new Position(10, 20),\n * new Rotation(90),\n * ['pin-id-1', 'pin-id-2']\n * );\n * ```\n */\n constructor(\n type: ComponentType,\n position: Position,\n rotation: Rotation,\n pins: ReadonlyArray<UUID>\n ) {\n this.id = generateUUID();\n this.type = type;\n this.position = position;\n this.rotation = rotation;\n\n // add a check on the unicity of pins\n if (new Set(pins).size !== pins.length) {\n const duplicates = pins.filter((item, index) => pins.indexOf(item) !== index);\n throw new Error(\n `Duplicate pin names are not allowed: ${[...new Set(duplicates)].join(', ')}`\n );\n }\n\n this.pins = pins;\n // instanciate component config from metadata's default config\n this.config = new Map<string, string>(COMPONENT_TYPE_METADATA[type].config);\n }\n\n getPinLabel(pinId: UUID): string | undefined {\n const pinIndex = this.pins.indexOf(pinId);\n if (pinIndex === -1) {\n return undefined;\n }\n const pinLabels = getComponentTypeMetadata(this.type).pins.keys();\n // convert to array to access by index\n return Array.from(pinLabels)[pinIndex] || undefined;\n }\n\n setAllParameters(config: Map<string, string>): void {\n this.config = new Map<string, string>(config);\n }\n\n setParameter(key: string, value: string): void {\n this.config.set(key, value);\n }\n\n /**\n * Update the component's position.\n *\n * @param newPosition - The new position for the component\n *\n * @example\n * ```typescript\n * const component = circuit.getComponent(componentId);\n * component.setPosition(new Position(15, 25));\n * ```\n */\n setPosition(newPosition: Position): void {\n Object.defineProperty(this, 'position', {\n value: newPosition,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n }\n\n /**\n * Update the component's rotation.\n *\n * @param newRotation - The new rotation for the component\n *\n * @example\n * ```typescript\n * const component = circuit.getComponent(componentId);\n * component.setRotation(new Rotation(90));\n * ```\n */\n setRotation(newRotation: Rotation): void {\n Object.defineProperty(this, 'rotation', {\n value: newRotation,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n }\n\n /**\n * Serialize component to JSON.\n *\n * @returns Plain object representation\n *\n * @example\n * ```typescript\n * const json = component.toJSON();\n * console.log(json);\n * // {\n * // id: \"550e8400-...\",\n * // type: \"battery\",\n * // position: { x: 10, y: 20 },\n * // rotation: 90,\n * // pins: ['pin-uuid-1', 'pin-uuid-2']\n * // }\n * ```\n */\n toJSON(): {\n id: UUID;\n type: ComponentType;\n position: { x: number; y: number };\n rotation: number;\n pins: UUID[];\n config: { [key: string]: string };\n } {\n return {\n id: this.id,\n type: this.type,\n position: this.position.toJSON(),\n rotation: this.rotation.toJSON(),\n pins: [...this.pins],\n config: Object.fromEntries(this.config),\n };\n }\n\n /**\n * Deserialize component from JSON.\n *\n * @param json - Component data\n * @returns Component instance\n *\n * @example\n * ```typescript\n * const json = {\n * id: \"550e8400-...\",\n * type: \"battery\",\n * position: { x: 10, y: 20 },\n * rotation: 90,\n * pins: ['1b4f6f3c-ce ....', '2c5e7g4d-df ...'],\n * config: { \"voltage\": \"5V\" }\n * };\n *\n * const component = Component.fromJSON(json);\n * console.log(component.position.x); // 10\n * ```\n */\n static fromJSON(json: {\n id: UUID;\n type: ComponentType;\n position: { x: number; y: number };\n rotation: number;\n pins: UUID[];\n config: { [key: string]: string };\n }): Component {\n // Create temporary component to get position/rotation instances\n const component = new Component(\n json.type,\n Position.fromJSON(json.position),\n Rotation.fromJSON(json.rotation),\n json.pins\n );\n component.config = new Map<string, string>(Object.entries(json.config));\n\n // Override the generated ID with the one from JSON\n // Using Object.defineProperty to bypass readonly\n Object.defineProperty(component, 'id', {\n value: json.id,\n writable: false,\n enumerable: true,\n configurable: false,\n });\n\n return component;\n }\n}\n","/**\n * Complete snapshot of circuit electrical state at a specific simulation tick\n * @module core/simulation\n */\n\nimport type { UUID } from '../types/Identifier.js';\nimport type { ComponentState, NodeElectricalState } from './states';\n\n/**\n * Represents the complete electrical state of the circuit at a specific time step.\n * Immutable snapshot that can be stored in history.\n *\n * @public\n */\nexport class SimulationState {\n /**\n * Current simulation step number (starts at 0).\n * @readonly\n */\n tick: number;\n\n /**\n * Electrical state for each ENode (component pins and branching points).\n * Key: ENode UUID, Value: NodeElectricalState\n * @readonly\n */\n readonly nodeStates: ReadonlyMap<UUID, NodeElectricalState>;\n\n /**\n * Electrical state for each Wire connecting ENodes.\n * Key: Wire UUID, Value: NodeElectricalState\n * @readonly\n */\n readonly wireStates: ReadonlyMap<UUID, NodeElectricalState>;\n\n /**\n * Component-specific state for each component.\n * Key: Component UUID, Value: ComponentState subclass\n * @readonly\n */\n readonly componentStates: ReadonlyMap<UUID, ComponentState>;\n\n /**\n * Create a new simulation state snapshot.\n *\n * @param tick - Current simulation step number\n */\n constructor(tick: number) {\n if (tick < 0 || !Number.isInteger(tick)) {\n throw new RangeError(`Tick must be a non-negative integer (got ${tick})`);\n }\n\n this.tick = tick;\n this.nodeStates = new Map();\n this.wireStates = new Map();\n this.componentStates = new Map();\n }\n\n setTick(tick: number) {\n this.tick = tick;\n }\n\n /**\n * Create a deep copy of this state for historical storage.\n *\n * @returns Cloned SimulationState\n */\n clone(): SimulationState {\n const clonedState = new SimulationState(this.tick);\n\n const clonedNodeStates: Map<UUID, NodeElectricalState> = new Map();\n for (const [id, state] of this.nodeStates.entries()) {\n clonedNodeStates.set(id, { ...state });\n }\n const clonedWireStates: Map<UUID, NodeElectricalState> = new Map();\n for (const [id, state] of this.wireStates.entries()) {\n clonedWireStates.set(id, { ...state });\n }\n const clonedComponentStates: Map<UUID, ComponentState> = new Map();\n for (const [id, state] of this.componentStates.entries()) {\n clonedComponentStates.set(\n id,\n Object.assign(Object.create(Object.getPrototypeOf(state)), state)\n );\n }\n\n Object.defineProperty(clonedState, 'nodeStates', {\n value: clonedNodeStates,\n writable: false,\n configurable: false,\n enumerable: true,\n });\n Object.defineProperty(clonedState, 'wireStates', {\n value: clonedWireStates,\n writable: false,\n configurable: false,\n enumerable: true,\n });\n Object.defineProperty(clonedState, 'componentStates', {\n value: clonedComponentStates,\n writable: false,\n configurable: false,\n enumerable: true,\n });\n\n return clonedState;\n }\n}\n","/**\n * Manages simulation state and optional history tracking\n * @module core/simulation\n */\n\nimport { SimulationState } from './SimulationState.js';\n\n/**\n * Manages current simulation state and historical state storage.\n * Uses a circular buffer for efficient memory-bounded history.\n *\n * @public\n */\nexport class StateManager {\n private currentState: SimulationState;\n private history: SimulationState[];\n private readonly historyEnabled: boolean;\n private readonly historyLimit: number;\n private historyWriteIndex: number;\n\n /**\n * Create a new state controllerType.\n *\n * @param enableHistory - Whether to store state history (default: false)\n * @param historyLimit - Maximum number of historical states to keep (default: 1000)\n */\n constructor(enableHistory: boolean = false, historyLimit: number = 1000) {\n if (historyLimit < 1) {\n throw new RangeError(`historyLimit must be at least 1 (got ${historyLimit})`);\n }\n\n this.historyEnabled = enableHistory;\n this.historyLimit = historyLimit;\n this.currentState = new SimulationState(0);\n this.history = [];\n this.historyWriteIndex = 0;\n }\n\n /**\n * Get the current simulation state.\n *\n * @returns Current state (mutable for simulation controller use)\n */\n getCurrentState(): SimulationState {\n return this.currentState;\n }\n\n /**\n * Get current tick number.\n *\n * @returns Current simulation tick\n */\n getCurrentTick(): number {\n return this.currentState.tick;\n }\n\n /**\n * Advance to next tick, optionally saving current state to history.\n * Creates a new SimulationState for the next tick.\n *\n * @returns New current state for the next tick\n */\n advanceToNextTick(): SimulationState {\n const nextTick = this.currentState.tick + 1;\n\n // Save current state to history if enabled\n if (this.historyEnabled) {\n this.saveToHistory(this.currentState.clone());\n }\n\n // update current state to new tick\n this.currentState.tick = nextTick;\n\n return this.currentState;\n }\n\n /**\n * Get a historical state by tick number.\n * Only works if history is enabled.\n *\n * @param tick - Tick number to retrieve\n * @returns State at that tick, or undefined if not available\n */\n getStateAtTick(tick: number): SimulationState | undefined {\n if (!this.historyEnabled) {\n return undefined;\n }\n\n return this.history.find((state) => state.tick === tick);\n }\n\n /**\n * Get all available historical states.\n * Returns empty array if history is disabled.\n *\n * @returns Array of historical states, sorted by tick (oldest first)\n */\n getHistory(): ReadonlyArray<SimulationState> {\n if (!this.historyEnabled) {\n return [];\n }\n\n // Return sorted copy\n return [...this.history].sort((a, b) => a.tick - b.tick);\n }\n\n /**\n * Get the oldest tick number available in history.\n *\n * @returns Oldest tick number, or undefined if no history\n */\n getOldestTick(): number | undefined {\n if (!this.historyEnabled || this.history.length === 0) {\n return undefined;\n }\n\n return Math.min(...this.history.map((state) => state.tick));\n }\n\n /**\n * Get the newest tick number in history (not including current tick).\n *\n * @returns Newest historical tick, or undefined if no history\n */\n getNewestHistoricalTick(): number | undefined {\n if (!this.historyEnabled || this.history.length === 0) {\n return undefined;\n }\n\n return Math.max(...this.history.map((state) => state.tick));\n }\n\n /**\n * Clear all history.\n */\n clearHistory(): void {\n this.history = [];\n this.historyWriteIndex = 0;\n }\n\n /**\n * Reset to tick 0, clearing current state and all history.\n */\n reset(): void {\n this.currentState = new SimulationState(0);\n this.clearHistory();\n }\n\n /**\n * Check if history tracking is enabled.\n *\n * @returns True if history is enabled\n */\n isHistoryEnabled(): boolean {\n return this.historyEnabled;\n }\n\n /**\n * Get the configured history limit.\n *\n * @returns Maximum number of historical states\n */\n getHistoryLimit(): number {\n return this.historyLimit;\n }\n\n /**\n * Get current history size.\n *\n * @returns Number of states in history\n */\n getHistorySize(): number {\n return this.history.length;\n }\n\n /**\n * Save a state to history using circular buffer.\n * Private helper for advanceToNextTick.\n *\n * @param state - State to save\n */\n private saveToHistory(state: SimulationState): void {\n if (this.history.length < this.historyLimit) {\n // History not yet full, just append\n this.history.push(state);\n } else {\n // Circular buffer: overwrite oldest entry\n this.history[this.historyWriteIndex] = state;\n this.historyWriteIndex = (this.historyWriteIndex + 1) % this.historyLimit;\n }\n }\n}\n","/**\n * Min-heap priority queue for scheduled events\n * @module core/simulation\n */\n\nimport type { ScheduledEvent } from './types/ScheduledEvent.js';\n\n/**\n * Min-heap priority queue for scheduling future component transitions.\n * Events are ordered by readyAtTick (earliest first).\n * Events with same readyAtTick are returned in FIFO order (by scheduledAtTick).\n *\n * @public\n */\nexport class EventQueue {\n private heap: ScheduledEvent[];\n\n /**\n * Create a new empty event queue.\n */\n constructor() {\n this.heap = [];\n }\n\n /**\n * Schedule a future event.\n * Inserted with O(log N) complexity using heap operations.\n *\n * @param event - Event to schedule\n */\n schedule(event: ScheduledEvent): void {\n if (event.readyAtTick < event.scheduledAtTick) {\n throw new RangeError(\n `readyAtTick (${event.readyAtTick}) cannot be before scheduledAtTick (${event.scheduledAtTick})`\n );\n }\n\n this.heap.push(event);\n this.bubbleUp(this.heap.length - 1);\n }\n\n /**\n * Get all events ready to fire at or before current tick.\n * Returns events in FIFO order for same readyAtTick.\n * Removes returned events from the queue.\n *\n * @param currentTick - Current simulation tick\n * @returns Array of ready events (removed from queue)\n */\n getReadyEvents(currentTick: number): ScheduledEvent[] {\n const ready: ScheduledEvent[] = [];\n\n while (this.heap.length > 0 && this.heap[0]!.readyAtTick <= currentTick) {\n const event = this.extractMin();\n if (event) {\n ready.push(event);\n }\n }\n\n // Sort by scheduledAtTick for FIFO within same readyAtTick\n ready.sort((a, b) => {\n if (a.readyAtTick === b.readyAtTick) {\n return a.scheduledAtTick - b.scheduledAtTick;\n }\n return a.readyAtTick - b.readyAtTick;\n });\n\n return ready;\n }\n\n /**\n * Check if any events are pending.\n *\n * @returns True if queue contains events\n */\n hasEvents(): boolean {\n return this.heap.length > 0;\n }\n\n /**\n * Clear all pending events.\n */\n clear(): void {\n this.heap = [];\n }\n\n /**\n * Get number of pending events.\n *\n * @returns Event count\n */\n size(): number {\n return this.heap.length;\n }\n\n private bubbleUp(index: number): void {\n while (index > 0) {\n const parentIndex = Math.floor((index - 1) / 2);\n if (this.heap[index]!.readyAtTick < this.heap[parentIndex]!.readyAtTick) {\n [this.heap[index], this.heap[parentIndex]] = [this.heap[parentIndex]!, this.heap[index]!];\n index = parentIndex;\n } else {\n break;\n }\n }\n }\n\n private bubbleDown(index: number): void {\n const length = this.heap.length;\n\n while (true) {\n const leftChild = 2 * index + 1;\n const rightChild = 2 * index + 2;\n let smallest = index;\n\n if (\n leftChild < length &&\n this.heap[leftChild]!.readyAtTick < this.heap[smallest]!.readyAtTick\n ) {\n smallest = leftChild;\n }\n\n if (\n rightChild < length &&\n this.heap[rightChild]!.readyAtTick < this.heap[smallest]!.readyAtTick\n ) {\n smallest = rightChild;\n }\n\n if (smallest !== index) {\n [this.heap[index], this.heap[smallest]] = [this.heap[smallest]!, this.heap[index]!];\n index = smallest;\n } else {\n break;\n }\n }\n }\n\n private extractMin(): ScheduledEvent | undefined {\n if (this.heap.length === 0) {\n return undefined;\n }\n\n const min = this.heap[0];\n const last = this.heap.pop();\n\n if (this.heap.length > 0 && last) {\n this.heap[0] = last;\n this.bubbleDown(0);\n }\n\n return min;\n }\n}\n","/**\n * Tracks which circuit elements have changed state during the current tick\n * @module core/simulation\n */\n\nimport type { UUID } from '../types/Identifier.js';\n\n/**\n * Dirty elements collected during a tick, returned by getDirtyElements().\n *\n * @public\n */\nexport interface DirtyElements {\n /**\n * Components that changed state.\n */\n readonly components: ReadonlySet<UUID>;\n\n /**\n * Wires that changed electrical state.\n */\n readonly wires: ReadonlySet<UUID>;\n\n /**\n * ENodes that changed electrical state.\n */\n readonly enodes: ReadonlySet<UUID>;\n}\n\n/**\n * Tracks per-element changes for optimized state propagation.\n * Provides granular dirty tracking at component/wire/enode level.\n *\n * Used to avoid re-processing unchanged elements during simulation ticks.\n *\n * @public\n */\nexport class DirtyTracker {\n private dirtyComponents: Set<UUID>;\n private dirtyWires: Set<UUID>;\n private dirtyEnodes: Set<UUID>;\n\n /**\n * Create a new dirty tracker with no marked elements.\n */\n constructor() {\n this.dirtyComponents = new Set();\n this.dirtyWires = new Set();\n this.dirtyEnodes = new Set();\n }\n\n /**\n * Mark a component as having changed state this tick.\n *\n * @param componentId - UUID of the component\n */\n markComponentDirty(componentId: UUID): void {\n this.dirtyComponents.add(componentId);\n }\n\n /**\n * Mark a wire as having changed electrical state this tick.\n *\n * @param wireId - UUID of the wire\n */\n markWireDirty(wireId: UUID): void {\n this.dirtyWires.add(wireId);\n }\n\n /**\n * Mark an ENode as having changed electrical state this tick.\n *\n * @param enodeId - UUID of the ENode\n */\n markEnodeDirty(enodeId: UUID): void {\n this.dirtyEnodes.add(enodeId);\n }\n\n /**\n * Set the entire set of dirty components. Should be only used at CircuitRunner initialization.\n * @param componentIds\n */\n setDirtyComponents(componentIds: Set<UUID>): void {\n this.dirtyComponents = new Set(componentIds);\n }\n\n /**\n * Set the entire set of dirty components. Should be only used at CircuitRunner initialization.\n * @param enodeIds\n */\n setDirtyEnodes(enodeIds: Set<UUID>): void {\n this.dirtyEnodes = new Set(enodeIds);\n }\n\n /**\n * Set the entire set of dirty components. Should be only used at CircuitRunner initialization.\n * @param wireIds\n */\n setDirtyWires(wireIds: Set<UUID>): void {\n this.dirtyWires = new Set(wireIds);\n }\n\n /**\n * Get all dirty elements and clear the tracker.\n * This is typically called at the end of a tick to collect changes.\n *\n * @returns Object containing sets of dirty component/wire/enode UUIDs\n */\n getDirtyElements(): DirtyElements {\n const result: DirtyElements = {\n components: new Set(this.dirtyComponents),\n wires: new Set(this.dirtyWires),\n enodes: new Set(this.dirtyEnodes),\n };\n\n this.clear();\n\n return result;\n }\n\n /**\n * Check if any elements are marked dirty.\n *\n * @returns True if at least one element is dirty\n */\n hasDirtyElements(): boolean {\n return this.dirtyComponents.size > 0 || this.dirtyWires.size > 0 || this.dirtyEnodes.size > 0;\n }\n\n /**\n * Clear all dirty markers without returning them.\n */\n clear(): void {\n this.dirtyComponents.clear();\n this.dirtyWires.clear();\n this.dirtyEnodes.clear();\n }\n\n /**\n * Get current count of dirty components (for debugging/metrics).\n *\n * @returns Number of dirty components\n */\n getDirtyComponentCount(): number {\n return this.dirtyComponents.size;\n }\n\n /**\n * Get current count of dirty wires (for debugging/metrics).\n *\n * @returns Number of dirty wires\n */\n getDirtyWireCount(): number {\n return this.dirtyWires.size;\n }\n\n /**\n * Get current count of dirty enodes (for debugging/metrics).\n *\n * @returns Number of dirty enodes\n */\n getDirtyEnodeCount(): number {\n return this.dirtyEnodes.size;\n }\n}\n","/**\n * Simulation speed and timing constants\n * @module core/simulation/types\n */\n\n/**\n * Simulation speed bounds and defaults for ticks per second (TPS).\n * @public\n */\nexport const SIMULATION_SPEED = {\n /**\n * Minimum simulation speed in ticks per second\n */\n MIN_TPS: 1,\n\n /**\n * Maximum simulation speed in ticks per second\n */\n MAX_TPS: 50,\n\n /**\n * Default simulation speed in ticks per second\n */\n DEFAULT_TPS: 2,\n\n /**\n * Default tick interval in milliseconds (1000 / DEFAULT_TPS)\n */\n DEFAULT_INTERVAL_MS: 500,\n} as const;\n\n/**\n * Default transition timing values for components.\n * @public\n */\nexport const TRANSITION_DEFAULTS = {\n /**\n * Default transitionSpan for relays and transistors in ticks (instant transition)\n */\n TRANSITION_SPAN_TICKS: 1,\n\n /**\n * Default transitionUserSpan for switches in milliseconds\n */\n TRANSITION_USER_SPAN_MS: 200,\n} as const;\n","/**\n * Main simulation controller for discrete-time circuit simulation\n * @module core/simulation\n */\n\nimport type { Circuit } from '../Circuit.js';\nimport type { RunnerOptions } from './types/RunnerOptions.js';\nimport type { UserCommand } from './types/UserCommand.js';\nimport type { NodeElectricalState } from './states/NodeElectricalState.js';\nimport type { ComponentState } from './states/ComponentState.js';\nimport { SimulationState } from './SimulationState.js';\nimport { StateManager } from './StateManager.js';\nimport { EventQueue } from './EventQueue.js';\nimport { DirtyTracker } from './DirtyTracker.js';\nimport { BehaviorRegistry } from './behaviors';\nimport type { UUID } from '../types/Identifier.js';\nimport { ENodeSourceType } from '../types/ENodeSourceType';\nimport type { ReachabilityResult } from './types/ReachabilityResult';\nimport type { ENode } from '../ENode';\nimport { ENodeType } from '../types/ENodeType';\nimport type { Component } from '../Component';\nimport type { BehaviorResult } from './behaviors/ComponentBehavior';\nimport type { RunnerResult } from './types/RunnerResult';\n\n/**\n * Main circuit simulation controller.\n * Manages discrete-time simulation with event-driven state propagation.\n *\n * Features:\n * - Boolean electrical state (voltage/current present or not)\n * - Event-driven delayed transitions\n * - Dirty tracking for optimization\n * - Configurable history storage\n * - Registry-based component behaviors\n *\n * @public\n */\nexport class CircuitRunner {\n public readonly circuit: Circuit;\n public readonly stateManager: StateManager;\n public readonly eventQueue: EventQueue;\n public readonly commands: Map<UUID, UserCommand>;\n public readonly dirtyTracker: DirtyTracker;\n public readonly behaviorRegistry: BehaviorRegistry;\n\n /**\n * Create a new circuit simulation runner.\n *\n * @param circuit - The circuit topology to simulate\n * @param behaviorRegistry - Registry of component behaviors\n * @param options - Simulation options (history settings)\n */\n constructor(circuit: Circuit, behaviorRegistry: BehaviorRegistry, options: RunnerOptions = {}) {\n this.circuit = circuit;\n this.behaviorRegistry = behaviorRegistry;\n\n const enableHistory = options.enableHistory ?? false;\n const historyLimit = options.historyLimit ?? 1000;\n\n this.stateManager = new StateManager(enableHistory, historyLimit);\n this.eventQueue = new EventQueue();\n this.commands = new Map<UUID, UserCommand>();\n this.dirtyTracker = new DirtyTracker();\n\n // Initialize simulation state\n try {\n this.initializeState();\n } catch (e) {\n console.error('Error during CircuitRunner initialization:', e);\n throw e;\n }\n }\n\n /**\n * Execute one simulation tick.\n * Process scheduled events, update state (electrical propagation), process user commands and advance tick.\n *\n * @returns the result of the tick execution\n */\n tick(): RunnerResult {\n const eventQueueStartSize = this.eventQueue.size();\n const currentTick = this.stateManager.getCurrentTick();\n\n // 1. Process scheduled events ready at this tick end\n const eventResults = this.applyReadyEvents(currentTick + 1);\n\n // 2. Update state\n const result = this.updateState(currentTick + 1);\n result.firedEventCount = eventResults.length;\n\n // 3. Process user commands scheduled for this tick\n const userCommandResults = this.processCommands();\n result.processedCommandCount = userCommandResults.length;\n\n result.scheduledEventCount =\n this.eventQueue.size() + result.firedEventCount - eventQueueStartSize;\n\n // 3H. due to orchestration difficulties this hotfix handles component dirty tracking\n for (const eventResult of eventResults) {\n if (eventResult.hasChanged) {\n this.dirtyTracker.markComponentDirty(eventResult.componentState.componentId);\n }\n }\n result.componentUpdateCount = this.dirtyTracker.getDirtyComponentCount();\n\n // 4. Advance to next tick\n this.stateManager.advanceToNextTick();\n result.endTick = this.stateManager.getCurrentTick();\n return result;\n }\n\n /**\n * Execute multiple simulation ticks.\n *\n * @param count - Number of ticks to execute\n * @returns an array of RunnerResult for each tick executed\n */\n tickN(count: number): RunnerResult[] {\n if (count < 1) {\n throw new RangeError(`Tick count must be at least 1 (got ${count})`);\n }\n\n const results = [];\n for (let i = 0; i < count; i++) {\n results.push(this.tick());\n }\n\n return results;\n }\n\n /**\n * Reset simulation to tick 0.\n * Clears all state, history, and scheduled events.\n */\n reset(): void {\n this.stateManager.reset();\n this.eventQueue.clear();\n this.dirtyTracker.clear();\n this.initializeState();\n }\n\n /**\n * Get current simulation tick number.\n *\n * @returns Current tick\n */\n getCurrentTick(): number {\n return this.stateManager.getCurrentTick();\n }\n\n /**\n * Get current simulation state snapshot.\n *\n * @returns Current state (readonly)\n */\n getCurrentState(): SimulationState {\n return this.stateManager.getCurrentState();\n }\n\n /**\n * Get electrical state of a specific ENode.\n *\n * @param enodeId - UUID of the ENode\n * @returns Electrical state, or undefined if not found\n */\n getEnodeState(enodeId: UUID): NodeElectricalState | undefined {\n return this.stateManager.getCurrentState().nodeStates.get(enodeId);\n }\n\n /**\n * Get electrical state of a specific Wire.\n *\n * @param wireId - UUID of the Wire\n * @returns Electrical state, or undefined if not found\n */\n getWireState(wireId: UUID): NodeElectricalState | undefined {\n return this.stateManager.getCurrentState().wireStates.get(wireId);\n }\n\n /**\n * Get component state for a specific component.\n *\n * @param componentId - UUID of the component\n * @returns Component state, or undefined if not found\n */\n getComponentState(componentId: UUID): ComponentState | undefined {\n return this.stateManager.getCurrentState().componentStates.get(componentId);\n }\n\n /**\n * Get historical state at a specific tick.\n * Only works if history is enabled.\n *\n * @param tick - Tick number to retrieve\n * @returns Historical state, or undefined if not available\n */\n getStateAtTick(tick: number): SimulationState | undefined {\n return this.stateManager.getStateAtTick(tick);\n }\n\n /**\n * Check if a component is registered in behavior registry.\n *\n * @param componentType - Component type to check\n * @returns True if behavior is registered\n */\n hasBehavior(componentType: string): boolean {\n return this.behaviorRegistry.has(componentType);\n }\n\n /**\n * Submit a user command to execute at the next tick.\n * only one command per component per tick is allowed.\n * Subsequent commands for the same component at this tick will be discarded.\n *\n * @param command - User command to submit\n */\n submitCommand(command: UserCommand): boolean {\n if (!this.circuit.hasComponent(command.targetId)) {\n throw Error(`Cannot submit command for unknown component ID '${command.targetId}'`);\n }\n if (this.commands.has(command.targetId)) {\n return false; // currently we only allow one command per component and tick\n }\n command.scheduledAtTick = this.getCurrentTick();\n this.commands.set(command.targetId, command);\n return true;\n }\n\n /**\n * Process all scheduled user commands.\n * Mark changed components as Dirty and enqueue consequent scheduled events\n * Finally clears command queue after processing.\n *\n * @returns Array of BehaviorResult for each processed command\n */\n private processCommands(): BehaviorResult[] {\n const currentState = this.stateManager.getCurrentState();\n\n const results: BehaviorResult[] = [];\n\n for (const command of this.commands.values()) {\n const component = this.circuit.getComponent(command.targetId) as Component;\n const behavior = this.behaviorRegistry.get(component.type)!;\n\n const result = behavior.onUserCommand(\n component,\n currentState.componentStates.get(component.id)!,\n command\n );\n for (const event of result.scheduledEvents) {\n this.eventQueue.schedule(event);\n }\n results.push(result);\n if (result.hasChanged) {\n this.dirtyTracker.markComponentDirty(component.id);\n }\n }\n this.commands.clear();\n\n return results;\n }\n\n /**\n * Helper function to extract initializationOrder from component config.\n * Returns numeric order value, with empty string or null defaulting to 0.\n *\n * @param config - Component configuration map\n * @returns Order value (lower = processed first)\n */\n private getInitializationOrder(config: Map<string, string>): number {\n const value = config.get('initializationOrder');\n if (!value || value === '') return 0;\n const parsed = parseInt(value, 10);\n return isNaN(parsed) ? 0 : parsed;\n }\n\n /**\n * Initialize simulation state for all components.\n * Called on construction and reset.\n *\n * Uses order-based initialization to resolve feedback loops:\n * 1. Components are grouped by initializationOrder (higher = processed LAST)\n * 2. Within each group, components are sorted by UUID (ascending) for determinism\n * 3. Conductivity is propagated after each component\n *\n * In feedback circuits, the component processed LAST \"wins\" because earlier\n * components react to the initial symmetric state and open, while later\n * components see the updated (asymmetric) state and stay closed.\n */\n private initializeState(): RunnerResult {\n const currentState = this.stateManager.getCurrentState();\n\n // Initialize component states using behaviors\n for (const component of this.circuit.getAllComponents()) {\n if (component.pins.length < 1) continue;\n\n const behavior = this.behaviorRegistry.get(component.type);\n if (!behavior) {\n // console.warn(\n // `No behavior registered for component type '${component.type}' (${component.id})`\n // );\n continue;\n }\n\n const initialState = behavior.createInitialState(component);\n (currentState.componentStates as Map<UUID, ComponentState>).set(component.id, initialState);\n\n // Mark component as dirty for initial evaluation\n this.dirtyTracker.markComponentDirty(component.id);\n }\n\n // Initialize all ENode initial states based on their topology source type\n for (const enode of this.circuit.getAllENodes()) {\n (currentState.nodeStates as Map<UUID, NodeElectricalState>).set(enode.id, {\n hasVoltage: enode.source === ENodeSourceType.Voltage,\n hasCurrent: enode.source === ENodeSourceType.Current,\n locked: !!enode.source,\n });\n }\n // Initialize all Wire states unlocked without voltage/current\n for (const wire of this.circuit.getAllWires()) {\n (currentState.wireStates as Map<UUID, NodeElectricalState>).set(wire.id, {\n hasVoltage: false,\n hasCurrent: false,\n locked: false,\n });\n }\n\n // Order-based initialization for feedback loop resolution\n // Group components by order level\n const allComponents = this.circuit.getAllComponents();\n const componentsByOrder = new Map<number, Component[]>();\n\n for (const component of allComponents) {\n const order = this.getInitializationOrder(component.config);\n const group = componentsByOrder.get(order) ?? [];\n group.push(component);\n componentsByOrder.set(order, group);\n }\n\n // Sort order levels (ascending - lower order first, higher order last)\n const sortedOrders = Array.from(componentsByOrder.keys()).sort((a, b) => a - b);\n\n // Sort components within each order group by UUID for determinism\n for (const order of sortedOrders) {\n const group = componentsByOrder.get(order)!;\n group.sort((a, b) => a.id.localeCompare(b.id));\n }\n\n // Iterate until stable state is reached (for feedback loop resolution)\n // This is necessary because feedback circuits may require multiple passes\n // to reach equilibrium after initial state changes propagate through the loop.\n //\n // KEY: During initialization, we fire events IMMEDIATELY after each component\n // processes (bypassing the normal tick delay). This allows the first component\n // in a feedback loop to complete its transition before the next component sees\n // the state, thereby breaking symmetry in cross-coupled feedback circuits.\n let hasChanges = true;\n let iterations = 0;\n const maxIterations = 100; // Safety limit to prevent infinite loops\n\n while (hasChanges && iterations < maxIterations) {\n hasChanges = false;\n iterations++;\n\n // Process each order group sequentially\n for (const order of sortedOrders) {\n const group = componentsByOrder.get(order)!;\n\n // Process each component sequentially with immediate event firing\n for (const component of group) {\n const behavior = this.behaviorRegistry.get(component.type);\n if (!behavior) continue;\n\n const componentState = currentState.componentStates.get(component.id);\n if (!componentState) continue;\n\n // Propagate before processing this component so it sees current electrical state\n this.propagateConductivity();\n\n // Let the component react to current pin states\n const result = behavior.onPinsChange(\n component,\n componentState,\n currentState.nodeStates,\n 0\n );\n\n // Update component state if it changed\n if (result.hasChanged) {\n hasChanges = true;\n (currentState.componentStates as Map<UUID, ComponentState>).set(\n component.id,\n result.componentState\n );\n }\n\n // During initialization, fire any scheduled events IMMEDIATELY\n // This is the key to breaking feedback symmetry: the first component\n // completes its full transition (e.g., opening → open) before the\n // next component in the feedback loop sees the new electrical state.\n for (const event of result.scheduledEvents) {\n const eventResult = behavior.onEventFiring(component, componentState, event);\n if (eventResult.hasChanged) {\n hasChanges = true;\n (currentState.componentStates as Map<UUID, ComponentState>).set(\n component.id,\n eventResult.componentState\n );\n }\n }\n }\n }\n }\n\n const result = this.updateState(0);\n\n // at initialization everything is dirty\n this.dirtyTracker.setDirtyComponents(\n new Set([...this.circuit.getAllComponents().map((c) => c.id)])\n );\n this.dirtyTracker.setDirtyEnodes(new Set([...this.circuit.getAllENodes().map((n) => n.id)]));\n this.dirtyTracker.setDirtyWires(new Set([...this.circuit.getAllWires().map((w) => w.id)]));\n\n return result;\n }\n\n /**\n * Core method that orchestrates nodes, wires and components state updates\n * enqueue resulting events and update dirty tracker accordingly\n * @param targetTick - Tick at which to perform the update\n */\n private updateState(targetTick: number): RunnerResult {\n const currentState = this.stateManager.getCurrentState();\n\n const { updatedNodes, updatedWires } = this.propagateConductivity();\n const componentsToAssess = this.circuit.getComponentsOfPins(updatedNodes);\n const results: BehaviorResult[] = [];\n\n const updatedComponents = new Set<UUID>();\n let eventCount = 0;\n\n // During initialization (tick 0), sort components by order to resolve feedback loops\n let sortedComponentIds = Array.from(componentsToAssess);\n if (targetTick === 0) {\n sortedComponentIds = sortedComponentIds.sort((idA, idB) => {\n const compA = this.circuit.getComponent(idA) as Component;\n const compB = this.circuit.getComponent(idB) as Component;\n const orderA = this.getInitializationOrder(compA.config);\n const orderB = this.getInitializationOrder(compB.config);\n\n // Lower order first, higher order last (ascending)\n if (orderA !== orderB) {\n return orderA - orderB;\n }\n\n // Tie-break by UUID (ascending)\n return idA.localeCompare(idB);\n });\n }\n\n for (const componentId of sortedComponentIds) {\n const component = this.circuit.getComponent(componentId) as Component;\n const behavior = this.behaviorRegistry.get(component.type);\n if (!behavior) {\n // console.warn(\n // `No behavior registered for component type '${component.type}' (${component.id})`\n // );\n continue;\n }\n const res = behavior.onPinsChange(\n component,\n currentState.componentStates.get(componentId)!,\n currentState.nodeStates,\n targetTick\n );\n if (res.hasChanged) {\n updatedComponents.add(componentId);\n results.push(res);\n }\n for (const event of res.scheduledEvents) {\n this.eventQueue.schedule(event);\n eventCount++;\n }\n }\n\n this.dirtyTracker.setDirtyComponents(updatedComponents);\n this.dirtyTracker.setDirtyEnodes(updatedNodes);\n this.dirtyTracker.setDirtyWires(updatedWires);\n\n return {\n startTick: this.getCurrentTick(),\n endTick: this.getCurrentTick(),\n componentUpdateCount: updatedComponents.size,\n nodeUpdateCount: updatedNodes.size,\n wireUpdateCount: updatedWires.size,\n processedCommandCount: 0,\n scheduledEventCount: eventCount,\n firedEventCount: 0,\n };\n }\n\n /**\n * runs BFS (Breadth First Search) on voltage and current conductivity\n * to propagate voltage/current conductivity\n * and update enodes/wires electrical states throughout the circuit\n * update is performed in place and updated nodes and wires returned\n */\n private propagateConductivity(): { updatedNodes: Set<UUID>; updatedWires: Set<UUID> } {\n const currentState = this.stateManager.getCurrentState();\n\n const updateConductivity = (\n type: ENodeSourceType\n ): {\n updatedNodes: Set<UUID>;\n updatedWires: Set<UUID>;\n } => {\n const updatedNodes = new Set<UUID>();\n const updatedWires = new Set<UUID>();\n\n const sources = this.circuit\n .getAllENodes()\n .filter((node) => node.source == type)\n .map((node) => node.id);\n const uncheckedNodes = new Set([\n ...this.circuit\n .getAllENodes()\n .filter((node) => !node.source)\n .map((node) => node.id),\n ]); // pool of all other nodes whose state is to assess\n const uncheckedWires = new Set([...this.circuit.getAllWires().map((wire) => wire.id)]); // pool of all other wires whose state is to assess\n\n const { nodes, wires } = this.computeReachability(\n type,\n sources,\n currentState.componentStates\n );\n\n const attribute = type == ENodeSourceType.Voltage ? 'hasVoltage' : 'hasCurrent';\n\n for (const nodeId of nodes) {\n const nodeState = currentState.nodeStates.get(nodeId);\n if (nodeState && !nodeState.locked) {\n if (!nodeState[attribute]) {\n nodeState[attribute] = true;\n updatedNodes.add(nodeId);\n }\n uncheckedNodes.delete(nodeId);\n }\n }\n // at this point all uncheckedNodes can be considered without conductivity : hence they are updated if necessary\n for (const nodeId of uncheckedNodes) {\n const nodeState = currentState.nodeStates.get(nodeId);\n if (nodeState && !nodeState.locked) {\n if (nodeState[attribute]) {\n nodeState[attribute] = false;\n updatedNodes.add(nodeId);\n }\n }\n }\n\n for (const wireId of wires) {\n const wireState = currentState.wireStates.get(wireId);\n if (!!wireState) {\n if (!wireState[attribute]) {\n wireState[attribute] = true;\n updatedWires.add(wireId);\n }\n uncheckedWires.delete(wireId);\n }\n }\n // at this point all uncheckedWires can be considered without conductivity : hence they are updated if necessary\n for (const wireId of uncheckedWires) {\n const wireState = currentState.wireStates.get(wireId);\n if (!!wireState) {\n if (wireState[attribute]) {\n wireState[attribute] = false;\n updatedWires.add(wireId);\n }\n }\n }\n\n return { updatedNodes, updatedWires };\n };\n\n const { updatedNodes: voltageUpdateNodes, updatedWires: voltageUpdatedWires } =\n updateConductivity(ENodeSourceType.Voltage);\n const { updatedNodes: currentUpdateNodes, updatedWires: currentUpdatedWires } =\n updateConductivity(ENodeSourceType.Current);\n\n return {\n updatedNodes: new Set([...voltageUpdateNodes, ...currentUpdateNodes]) as Set<UUID>,\n updatedWires: new Set([...voltageUpdatedWires, ...currentUpdatedWires]) as Set<UUID>,\n };\n }\n\n /**\n * given a conductivity conductivityType and a set of seed nodes, compute all reachable nodes and wires\n * depends on componentStates to determine if conductivity is allowed through components\n * this method doesn't mutate any state, it's a pure function\n * @param conductivityType\n * @param seeds\n * @param componentStates\n */\n private computeReachability(\n conductivityType: ENodeSourceType,\n seeds: UUID[],\n componentStates: ReadonlyMap<UUID, ComponentState>\n ): ReachabilityResult {\n const reachableNodes = new Set<UUID>();\n const reachableWires = new Set<UUID>();\n const frontier: UUID[] = [];\n\n // Seed the frontier\n for (const seed of seeds) {\n frontier.push(seed);\n reachableNodes.add(seed);\n }\n\n while (frontier.length > 0) {\n const currentId = frontier.shift() as UUID;\n\n // Traverse via wires\n for (const wire of this.circuit.getWiresByNode(currentId)) {\n const otherNodeId = wire.node1 === currentId ? wire.node2 : wire.node1;\n\n if (!reachableNodes.has(otherNodeId)) {\n reachableNodes.add(otherNodeId);\n frontier.push(otherNodeId);\n }\n if (!reachableWires.has(wire.id)) {\n reachableWires.add(wire.id);\n }\n }\n\n // Traverse through components in case of pin\n const node = this.circuit.getENode(currentId) as ENode;\n if (node.type === ENodeType.Pin) {\n const component = this.circuit.getComponent(node.component!) as Component;\n const behavior = this.behaviorRegistry.get(component.type);\n if (!behavior) {\n // console.warn(\n // `No behavior registered for component type '${component.type}' (${component.id})`\n // );\n continue;\n }\n\n const state = componentStates.get(component.id)!;\n\n for (const otherPinId of component.pins) {\n if (otherPinId === currentId) continue;\n if (reachableNodes.has(otherPinId)) continue;\n\n // Check if component allows traversal\n const res = behavior.allowConductivity(\n component,\n state,\n conductivityType,\n currentId,\n otherPinId\n );\n\n if (res) {\n reachableNodes.add(otherPinId);\n frontier.push(otherPinId);\n }\n }\n }\n }\n\n return { nodes: reachableNodes, wires: reachableWires };\n }\n\n /**\n * Fire ready events and update current state accordingly\n * eventual subsequent events are enqueued\n *\n * @param targetTick - Tick at which to process events\n * @param events - Events to apply\n * @param state - Current simulation state\n * @param targetTick - Target tick for event processing\n */\n private applyReadyEvents(targetTick: number): BehaviorResult[] {\n const currentState = this.stateManager.getCurrentState();\n const readyEvents = this.eventQueue.getReadyEvents(targetTick);\n\n const results: BehaviorResult[] = [];\n\n for (const event of readyEvents) {\n const component = this.circuit.getComponent(event.targetId) as Component;\n const behavior = this.behaviorRegistry.get(component.type);\n if (!behavior) {\n // console.warn(\n // `No behavior registered for component type '${component.type}' (${component.id})`\n // );\n continue;\n }\n\n const componentState = currentState.componentStates.get(component.id)!;\n const result = behavior.onEventFiring(component, componentState, event);\n for (const event of result.scheduledEvents) {\n this.eventQueue.schedule(event);\n }\n results.push(result);\n }\n\n return results;\n }\n}\n"],"names":["Position3D","x","y","z","other","json","CameraOptions","position","lookAtPosition","fov","near","far","ENodeSourceType","ComponentType","COMPONENT_TYPE_METADATA","getAllComponentTypes","getComponentTypeMetadata","type","ENodeType","generateUUID","hexDigits","sections","parts","length","part","i","randomByte","chars","variantIndex","Position","findPositionBestIndex","positions","target","minDistance","bestIndex","segmentStart","segmentEnd","distance","pointToSegmentDistance","point","dx","dy","segmentLengthSquared","t","closestX","closestY","simplifyPositions","tolerance","result","prev","current","next","areCollinear","a","b","c","crossProduct","Rotation","angle","Component","rotation","pins","duplicates","item","index","pinId","pinIndex","pinLabels","config","key","value","newPosition","newRotation","component","SimulationState","tick","clonedState","clonedNodeStates","id","state","clonedWireStates","clonedComponentStates","StateManager","enableHistory","historyLimit","nextTick","EventQueue","event","currentTick","ready","parentIndex","leftChild","rightChild","smallest","min","last","DirtyTracker","componentId","wireId","enodeId","componentIds","enodeIds","wireIds","SIMULATION_SPEED","TRANSITION_DEFAULTS","CircuitRunner","circuit","behaviorRegistry","options","e","eventQueueStartSize","eventResults","userCommandResults","eventResult","count","results","componentType","command","currentState","parsed","behavior","initialState","enode","wire","allComponents","componentsByOrder","order","group","sortedOrders","hasChanges","iterations","maxIterations","componentState","n","w","targetTick","updatedNodes","updatedWires","componentsToAssess","updatedComponents","eventCount","sortedComponentIds","idA","idB","compA","compB","orderA","orderB","res","updateConductivity","sources","node","uncheckedNodes","uncheckedWires","nodes","wires","attribute","nodeId","nodeState","wireState","voltageUpdateNodes","voltageUpdatedWires","currentUpdateNodes","currentUpdatedWires","conductivityType","seeds","componentStates","reachableNodes","reachableWires","frontier","seed","currentId","otherNodeId","otherPinId","readyEvents"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @module core
3
+ *
4
+ * Core object model for circuit topology representation.
5
+ *
6
+ * This module provides the foundational data structures for representing
7
+ * circuit topology with automatic lifecycle management:
8
+ *
9
+ * - **Circuit**: Container managing all circuit elements
10
+ * - **Component**: Base class for electrical components (lightbulbs, transistors, etc.)
11
+ * - **ENode**: Electrical connection points (component pins or wire branching points)
12
+ * - **Wire**: Connections between two ENodes
13
+ *
14
+ * Key features:
15
+ * - Automatic ENode lifecycle management
16
+ * - Cascade deletion (removing components removes pins and wires)
17
+ * - Orphaned cleanup (wires lacking one or two end enodes are removed)
18
+ * - Wire splitting with automatic branching point creation
19
+ * - Position tracking for 2D discrete grid rendering
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ export { CameraOptions } from './types/CameraOptions.js';
24
+ export type { ICameraOptions } from './types/CameraOptions.js';
25
+ export type { ComponentTypeMetadata } from './types/ComponentType.js';
26
+ export { ComponentType, COMPONENT_TYPE_METADATA, getAllComponentTypes, getComponentTypeMetadata, } from './types/ComponentType.js';
27
+ export { ENodeSourceType } from './types/ENodeSourceType.js';
28
+ export { ENodeType } from './types/ENodeType.js';
29
+ export type { UUID } from './types/Identifier.js';
30
+ export { generateUUID } from './types/Identifier.js';
31
+ export { Position, findPositionBestIndex, simplifyPositions } from './types/Position.js';
32
+ export { Position3D } from './types/Position3D.js';
33
+ export type { IPosition3D } from './types/Position3D.js';
34
+ export { Rotation } from './types/Rotation.js';
35
+ export { Circuit, CircuitMetadata } from './Circuit.js';
36
+ export type { ICircuitMetadata } from './Circuit.js';
37
+ export { Component } from './Component.js';
38
+ export { ENode } from './ENode.js';
39
+ export { Wire } from './Wire.js';
40
+ export type * from './simulation/index.js';
41
+ export * from './simulation/index.js';
42
+ export type * from './simulation/states/index.js';
43
+ export * from './simulation/states/index.js';
44
+ export type * from './simulation/behaviors/index.js';
45
+ export * from './simulation/behaviors/index.js';
46
+ export * from './setup.js';
47
+ //# sourceMappingURL=index.d.ts.map