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.
- package/LICENSE +21 -0
- package/README.md +6 -0
- package/dist/CircuitRunner-CAeE31M5.js +1477 -0
- package/dist/CircuitRunner-CAeE31M5.js.map +1 -0
- package/dist/core/index.d.ts +47 -0
- package/dist/core/index.js +1683 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +5621 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/scene/index.d.ts +42 -0
- package/dist/scene/index.js +27 -0
- package/dist/scene/index.js.map +1 -0
- package/dist/setup-FtJmrLda.js +8302 -0
- package/dist/setup-FtJmrLda.js.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-FtJmrLda.js","sources":["../src/scene/shared/EventEmitter.ts","../src/scene/shared/utils/GeometryUtils.ts","../src/scene/static/tools/BuildTool.ts","../src/scene/static/tools/AddComponentTool.ts","../src/scene/static/tools/MultiSelectTool.ts","../src/scene/shared/SelectionManager.ts","../src/scene/static/CircuitWriter.ts","../src/scene/shared/utils/CameraUtils.ts","../src/scene/shared/utils/LightingUtils.ts","../src/scene/shared/utils/LayerConstants.ts","../src/scene/shared/HoverManager.ts","../src/scene/shared/BranchingPointVisualFactory.ts","../src/scene/shared/utils/MaterialUtils.ts","../src/scene/shared/WireVisualManager.ts","../src/scene/shared/utils/Options.ts","../src/scene/shared/utils/ControlsUtils.ts","../src/scene/shared/AbstractCircuitController.ts","../node_modules/lil-gui/dist/lil-gui.esm.js","../src/scene/static/ConfigPanelManager.ts","../src/scene/static/CircuitController.ts","../src/scene/simulation/CircuitRunnerController.ts","../src/scene/CircuitEngine.ts","../src/scene/shared/components/FactoryRegistry.ts","../src/scene/shared/components/ComponentVisualFactory.ts","../src/scene/shared/utils/ColorUtils.ts","../src/scene/shared/components/DefaultVisualFactory.ts","../src/scene/shared/components/BatteryVisualFactory.ts","../src/scene/shared/components/LabelVisualFactory.ts","../src/scene/shared/components/LightbulbVisualFactory.ts","../src/scene/shared/components/RectangleLEDVisualFactory.ts","../src/scene/shared/components/RelayVisualFactory.ts","../src/scene/shared/components/SmallLEDVisualFactory.ts","../src/scene/shared/components/SwitchVisualFactory.ts","../src/scene/shared/components/TransistorVisualFactory.ts","../src/scene/setup.ts"],"sourcesContent":["/**\n * Type-safe Event Emitter\n * @module scene/shared/EventEmitter\n *\n * Provides type-safe event handling without external dependencies.\n * Generic EventMap type ensures compile-time type safety for event payloads.\n */\n\n/**\n * Generic event emitter with type-safe event emission and subscription\n *\n * @template EventMap - Map of event names to their payload types\n *\n * @example\n * ```typescript\n * interface MyEvents {\n * click: { x: number; y: number };\n * error: { message: string };\n * }\n *\n * const emitter = new EventEmitter<MyEvents>();\n * emitter.on('click', ({ x, y }) => console.log(x, y)); // Type-safe!\n * emitter.emit('click', { x: 10, y: 20 });\n * ```\n */\nexport class EventEmitter<EventMap extends Record<string, any>> {\n private listeners: Map<keyof EventMap, Function[]> = new Map();\n\n /**\n * Register an event listener\n *\n * @param event - Event name to listen for\n * @param callback - Function to call when event occurs\n *\n * @remarks\n * Same callback can be registered multiple times (will be called multiple times).\n * Callbacks are wrapped in try-catch to prevent errors from breaking emission.\n */\n on<K extends keyof EventMap>(event: K, callback: (payload: EventMap[K]) => void): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, []);\n }\n this.listeners.get(event)!.push(callback);\n }\n\n /**\n * Unregister an event listener\n *\n * @param event - Event name\n * @param callback - Function to remove (must be same reference used in on())\n *\n * @remarks\n * If callback was registered multiple times, only removes one registration.\n */\n off<K extends keyof EventMap>(event: K, callback: (payload: EventMap[K]) => void): void {\n const callbacks = this.listeners.get(event);\n if (callbacks) {\n const index = callbacks.indexOf(callback);\n if (index !== -1) {\n callbacks.splice(index, 1);\n }\n if (callbacks.length === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Emit an event to all registered listeners\n * This method is public so that tools may emit events directly on behalf of the EventEmitter owner (controller).\n *\n * @param event - Event name to emit\n * @param payload - Event-specific payload\n *\n * @remarks\n * Listeners are called in registration order.\n * Errors in callbacks are caught and logged but do not stop other callbacks.\n */\n emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n const callbacks = this.listeners.get(event);\n if (callbacks) {\n for (const callback of callbacks) {\n try {\n callback(payload);\n } catch (error) {\n // Prevent callback errors from breaking other callbacks\n console.error(`Error in event listener for '${String(event)}':`, error);\n }\n }\n }\n }\n\n /**\n * Remove all listeners for a specific event or all events\n *\n * @param event - Optional event name. If omitted, removes all listeners for all events.\n */\n removeAllListeners<K extends keyof EventMap>(event?: K): void {\n if (event !== undefined) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n\n /**\n * Get count of listeners for a specific event\n *\n * @param event - Event name\n * @returns Number of registered listeners\n */\n listenerCount<K extends keyof EventMap>(event: K): number {\n return this.listeners.get(event)?.length ?? 0;\n }\n\n /**\n * Register a listener that receives all events\n *\n * @param callback - Function called with event name and payload for every event\n * @returns Cleanup function to remove the listener\n *\n * @remarks\n * Useful for event forwarding/delegation patterns where you want to\n * re-emit all events from one emitter to another.\n *\n * @example\n * ```typescript\n * const cleanup = source.onAny((event, payload) => {\n * target.emit(event, payload);\n * });\n * // Later: cleanup();\n * ```\n */\n onAny(callback: <K extends keyof EventMap>(event: K, payload: EventMap[K]) => void): () => void {\n // Store the original emit\n const originalEmit = this.emit.bind(this);\n\n // Override emit to also call the callback\n this.emit = <K extends keyof EventMap>(event: K, payload: EventMap[K]) => {\n originalEmit(event, payload);\n try {\n callback(event, payload);\n } catch (error) {\n console.error(`Error in onAny listener for '${String(event)}':`, error);\n }\n };\n\n // Return cleanup function that restores original emit\n return () => {\n this.emit = originalEmit;\n };\n }\n}\n","/**\n * Geometry Utilities\n * @module scene/shared/utils/GeometryUtils\n *\n * Helper functions for creating Three.js geometries for grid and circuit elements\n */\n\nimport * as THREE from 'three';\nimport { Position, Rotation } from 'simple-circuit-engine/core';\nimport { ExtrudeGeometry } from 'three';\n\n/**\n * Create a grid helper for the scene\n *\n * @param size - Size of the grid\n * @param divisions - Number of grid divisions\n * @param colorCenterLine - Color for center lines\n * @param colorGrid - Color for grid lines\n * @returns GridHelper object\n */\nexport function createGridHelper(\n size: number,\n divisions: number,\n colorCenterLine: number,\n colorGrid: number\n): THREE.GridHelper {\n const grid = new THREE.GridHelper(size, divisions, colorCenterLine, colorGrid);\n grid.position.set(0, 0, 0);\n // set z-index to be behind other objects\n grid.renderOrder = -1;\n return grid;\n}\n\n/**\n * optimal number of grid divisions for a given size\n * @param size\n */\nexport function computeDivisionsForSize(size: number): number {\n if (size <= 10) return size;\n let basis = 10;\n let threshold = 10;\n if (size <= 30) {\n return basis + Math.floor((size - threshold) / 2);\n }\n basis = 20;\n threshold = 30;\n if (size <= 70) {\n return basis + Math.floor((size - threshold) / 4);\n }\n basis = 30;\n threshold = 70;\n if (size <= 150) {\n return basis + Math.floor((size - threshold) / 8);\n }\n basis = 40;\n threshold = 150;\n if (size <= 310) {\n return basis + Math.floor((size - threshold) / 16);\n }\n basis = 50;\n threshold = 310;\n if (size <= 630) {\n return basis + Math.floor((size - threshold) / 32);\n }\n basis = 60;\n threshold = 630;\n return Math.min(70, basis + Math.floor((size - threshold) / 64));\n}\n\n/**\n * Components, branching points and wires intermediate points snap to the nearest integer grid point.\n * @param position\n * @constructor\n */\nexport function nearestWorldSnapPosition(position: THREE.Vector3): THREE.Vector3 {\n return new THREE.Vector3(Math.round(position.x), 0, Math.round(position.z));\n}\n\n/**\n * Converts a world 3D position to the snapped 2D model grid position.\n * @param position\n * @constructor\n */\nexport function worldToGridPosition(position: THREE.Vector3): Position {\n return new Position(Math.round(position.x), Math.round(-position.z));\n}\n\n/**\n * Converts a model grid 2D position to the world 3D position.\n * @param position\n * @constructor\n */\nexport function gridToWorldPosition(position: Position): THREE.Vector3 {\n return new THREE.Vector3(position.x, 0, -position.y);\n}\n\n/**\n * Converts a world 3D rotation to the model grid 2D rotation.\n * @param rotation\n * @constructor\n */\nexport function worldToGridRotation(rotation: THREE.Euler): Rotation {\n return new Rotation(Math.round(THREE.MathUtils.radToDeg(-rotation.y)));\n}\n\n/**\n * Converts model grid 2D rotation to the world 3D rotation.\n * @param rotation\n * @constructor\n */\nexport function gridToWorldRotation(rotation: Rotation): THREE.Euler {\n return new THREE.Euler(0, THREE.MathUtils.degToRad(-rotation.angle), 0);\n}\n\n/**\n * Get the bounding box of a Three.js object in world space\n *\n * @param object - The Three.js object to get bounds for\n * @returns Box3 representing the world-space bounding box\n */\nexport function getObjectBoundingBox(object: THREE.Object3D): THREE.Box3 {\n const box = new THREE.Box3();\n box.setFromObject(object);\n return box;\n}\n\n/**\n * Project a 3D world position to 2D screen coordinates\n *\n * @param worldPosition - Position in world space\n * @param camera - Camera to use for projection\n * @param width - Viewport width in pixels\n * @param height - Viewport height in pixels\n * @returns Screen coordinates {x, y} where (0,0) is top-left\n */\nexport function worldToScreenPosition(\n worldPosition: THREE.Vector3,\n camera: THREE.Camera,\n width: number,\n height: number\n): { x: number; y: number } {\n const vector = worldPosition.clone();\n vector.project(camera);\n\n const x = ((vector.x + 1) / 2) * width;\n const y = ((-vector.y + 1) / 2) * height;\n\n return { x, y };\n}\n\n/**\n * Check if a 3D point (projected to screen space) is inside a 2D screen rectangle\n *\n * @param worldPosition - Position in world space\n * @param camera - Camera to use for projection\n * @param width - Viewport width in pixels\n * @param height - Viewport height in pixels\n * @param rect - Screen rectangle with min/max coordinates\n * @returns true if the projected point is inside the rectangle\n */\nexport function isPointInScreenRect(\n worldPosition: THREE.Vector3,\n camera: THREE.Camera,\n width: number,\n height: number,\n rect: { minX: number; minY: number; maxX: number; maxY: number }\n): boolean {\n const screen = worldToScreenPosition(worldPosition, camera, width, height);\n return (\n screen.x >= rect.minX && screen.x <= rect.maxX && screen.y >= rect.minY && screen.y <= rect.maxY\n );\n}\n\n/**\n * Check if an object's center point is inside a screen rectangle\n * Used for rectangle selection of components and branching points\n *\n * @param object - The Three.js object to check\n * @param camera - Camera to use for projection\n * @param width - Viewport width in pixels\n * @param height - Viewport height in pixels\n * @param rect - Screen rectangle with min/max coordinates\n * @returns true if object's center is inside the rectangle\n */\nexport function isObjectInScreenRect(\n object: THREE.Object3D,\n camera: THREE.Camera,\n width: number,\n height: number,\n rect: { minX: number; minY: number; maxX: number; maxY: number }\n): boolean {\n const worldPosition = new THREE.Vector3();\n object.getWorldPosition(worldPosition);\n return isPointInScreenRect(worldPosition, camera, width, height, rect);\n}\n\n/**\n * Create a ring geometry with given inner/outer radius and height\n * @param innerRadius\n * @param outerRadius\n * @param height\n * @param steps\n * @constructor\n */\nexport function RingGeometry(\n innerRadius: number,\n outerRadius: number,\n height: number,\n steps: number\n): ExtrudeGeometry {\n // Create the outer ring shape\n const shape = new THREE.Shape();\n shape.moveTo(outerRadius, 0);\n shape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false);\n\n // Create the inner ring path (hole)\n const holePath = new THREE.Path();\n holePath.moveTo(innerRadius, 0);\n holePath.absarc(0, 0, innerRadius, 0, Math.PI * 2, true);\n shape.holes.push(holePath);\n\n // Extrude settings\n const extrudeSettings = {\n depth: height,\n bevelEnabled: false,\n steps: steps,\n };\n\n // Create the extruded geometry\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n","/**\n * Build Tool Implementation\n * @module scene/static/tools/BuildTool\n *\n * Unified tool for all circuit editing operations:\n * - Wire creation between endpoints\n * - Element positioning (components, branching points, wire points)\n * - Component rotation\n * - Element deletion\n * - Branching point creation\n *\n * Replaces: PositionTool, WireTool, DeleteTool, BranchingPointTool\n */\n\nimport * as THREE from 'three';\nimport type { Euler } from 'three';\nimport { Line2 } from 'three/examples/jsm/lines/Line2.js';\nimport { type UUID, type ComponentType, ENodeSourceType } from 'simple-circuit-engine/core';\n\nimport type {\n IEditingTool,\n ToolType,\n CursorType,\n HoverableType,\n MonoSelectionData,\n HoveredElement,\n} from '../../shared/types';\nimport type { CircuitController } from '../CircuitController';\nimport {\n gridToWorldRotation,\n nearestWorldSnapPosition,\n worldToGridPosition,\n} from '../../shared/utils/GeometryUtils';\n\n\n/**\n * Build tool operating modes\n *\n * State transitions:\n * idle → wire_creation (click enode)\n * idle → component_drag (pointerdown on selected element)\n * idle → wire_drag (click wire or intermediate point)\n * idle → bp_drag (double-click+hold branching point)\n * {any active mode} → idle (pointerup, Escape, or operation complete)\n */\ntype BuildToolMode = 'idle' | 'wire_creation' | 'wire_drag' | 'component_drag' | 'bp_drag';\n\n/**\n * State during wire creation operation\n */\ninterface WireCreationState {\n /**\n * UUID of the source enode (pin or branching point)\n */\n sourceEnodeId: UUID;\n\n /**\n * World position of source enode (for preview line start)\n */\n sourcePosition: THREE.Vector3;\n\n /**\n * Preview wire object (Line2) rendered during creation\n * Follows cursor position until target selected\n */\n previewWire: Line2 | null;\n\n /**\n * Timestamp when operation started (for double-click disambiguation)\n */\n ts: number;\n}\n\n/**\n * State during wire intermediate point drag\n */\ninterface WireDragState {\n /**\n * UUID of wire being modified\n */\n wireId: UUID;\n\n /**\n * Index in intermediatePositions array\n * Or index where new point will be inserted\n */\n pointIndex: number;\n\n /**\n * Initial world position of drag start\n */\n initialPosition: THREE.Vector3;\n\n /**\n * Original intermediate positions (for cancel)\n * Snapshot of wire.intermediatePositions before drag\n */\n originalPositions: { x: number; y: number }[];\n\n /**\n * Target type determines behavior:\n * - 'intermediate': Dragging existing point\n * - 'new_intermediate': Creating and dragging new point\n */\n targetType: 'intermediate' | 'new_intermediate';\n}\n\n/**\n * State during component drag\n */\ninterface ComponentDragState {\n /**\n * UUID of component being dragged\n */\n componentId: UUID;\n\n /**\n * Initial world position (for cancel)\n */\n initialPosition: THREE.Vector3;\n}\n\n/**\n * State during branching point drag\n */\ninterface BPDragState {\n /**\n * UUID of branching point being dragged\n */\n enodeId: UUID;\n\n /**\n * Initial world position (for cancel)\n */\n initialPosition: THREE.Vector3;\n}\n\ninterface LastCancelledOp {\n /**\n * Type of operation that was cancelled\n */\n mode: BuildToolMode;\n /**\n * Timestamp of cancellation\n */\n ts: number;\n}\n\n/**\n * Clipboard data for copy-paste operations\n */\ninterface ClipboardData {\n /**\n * Type of component to paste\n */\n componentType: ComponentType;\n /**\n * Rotation of component to paste\n */\n rotation: Euler;\n /** Original configuration data for the component */\n config: Map<string, string>;\n /** Original pins sourceTypes */\n pinSources: Array<ENodeSourceType | undefined | null>;\n}\n\n/**\n * Returns the next sourceType in the cycle: null → Voltage → Current → null\n * @param current - Current source type\n * @returns Next source type in the cycle\n */\nfunction getNextSourceType(current: ENodeSourceType | undefined): ENodeSourceType | undefined {\n if (!current) return ENodeSourceType.Voltage;\n if (current === ENodeSourceType.Voltage) return ENodeSourceType.Current;\n return undefined; // Current → null\n}\n\n/**\n * Unified tool for building circuits\n * Implements all circuit editing functionality in a single tool\n */\nexport class BuildTool implements IEditingTool {\n readonly type: ToolType = 'build';\n\n private _controller: CircuitController;\n\n // Tool state\n private mode: BuildToolMode = 'idle';\n private lastCancelledOp: LastCancelledOp | null = null;\n\n // Mode-specific state\n private wireCreationState: WireCreationState | null = null;\n private wireDragState: WireDragState | null = null;\n private componentDragState: ComponentDragState | null = null;\n private bpDragState: BPDragState | null = null;\n\n // Clipboard for copy-paste operations\n private clipboard: ClipboardData | null = null;\n\n /**\n * Construct a new BuildTool instance\n * @param controller - The circuit scene controllerType instance\n */\n constructor(controller: CircuitController) {\n this._controller = controller;\n\n // Bind event handlers for stable references\n this.handlePointerDown = this.handlePointerDown.bind(this);\n this.handlePointerUp = this.handlePointerUp.bind(this);\n this.handleGridPositionMove = this.handleGridPositionMove.bind(this);\n this.handleKeyDown = this.handleKeyDown.bind(this);\n this.handleDblClick = this.handleDblClick.bind(this);\n }\n\n /**\n * Activate build tool and set up event listeners\n * Resets all tool state and attaches DOM event handlers\n */\n onActivate(): void {\n // Reset all state\n this.mode = 'idle';\n this.wireCreationState = null;\n this.wireDragState = null;\n this.componentDragState = null;\n this.bpDragState = null;\n this.lastCancelledOp = null;\n\n // Set up event listeners\n const container = this._controller.getContainer();\n\n container.addEventListener('pointerdown', this.handlePointerDown);\n container.addEventListener('pointerup', this.handlePointerUp);\n container.addEventListener('dblclick', this.handleDblClick);\n window.addEventListener('keydown', this.handleKeyDown);\n }\n\n /**\n * Deactivate build tool and clean up event listeners\n * Cancels any active operations and removes all event handlers\n */\n onDeactivate(): void {\n // Security : Cancel any active operations\n this.cancelOperation();\n\n const container = this._controller.getContainer();\n // Remove event listeners\n this._controller.off('gridPositionMove', this.handleGridPositionMove);\n container.removeEventListener('pointerdown', this.handlePointerDown);\n container.removeEventListener('pointerup', this.handlePointerUp);\n container.removeEventListener('dblclick', this.handleDblClick);\n window.removeEventListener('keydown', this.handleKeyDown);\n\n // Reset all state\n this.mode = 'idle';\n this.wireCreationState = null;\n this.wireDragState = null;\n this.componentDragState = null;\n this.bpDragState = null;\n this.lastCancelledOp = null;\n\n // Safety: re-enable camera controls\n const controls = this._controller.getControls();\n if (controls) {\n controls.enablePan = true;\n }\n }\n\n /**\n * Cancel current ongoing operation : can be called from outside if needed\n */\n cancelOperation(): void {\n if (this.mode === 'wire_creation') {\n this.cancelWireCreation();\n } else if (this.mode === 'wire_drag') {\n this.cancelWireDrag();\n } else if (this.mode === 'bp_drag') {\n this.cancelBPDrag();\n } else if (this.mode === 'component_drag') {\n this.cancelComponentDrag();\n }\n }\n\n /**\n * Get the current cursor type for this tool\n * Returns cursor based on current mode and hover state\n */\n getCursorType(): CursorType {\n const hoveredElement = this._controller.getHoveredElement();\n\n // During wire creation\n if (this.mode === 'wire_creation') {\n if (!this.isValidWireTarget(hoveredElement)) {\n return 'not-allowed';\n }\n return 'crosshair';\n }\n\n // During drag operations\n if (this.mode === 'component_drag' || this.mode === 'wire_drag' || this.mode === 'bp_drag') {\n return 'grabbing';\n }\n\n // Hover states (idle mode)\n if (hoveredElement) {\n // Can start wire from enode\n if (hoveredElement.type === 'enode') {\n return 'pointer';\n }\n\n // Can drag selected element\n const selection = this._controller.getSelectionManager().getSelection();\n if (selection && selection.kind === 'mono' && hoveredElement.id === selection.id) {\n return 'grab';\n }\n\n // Can interact with wire or component\n if (hoveredElement.type === 'wire' || hoveredElement.type === 'component') {\n return 'pointer';\n }\n }\n\n return 'default';\n }\n\n /**\n * Get preview objects to render in the scene\n * Returns array of preview objects currently visible\n */\n getPreviewObjects(): THREE.Object3D[] {\n const previews: THREE.Object3D[] = [];\n\n // Wire creation preview\n if (this.mode === 'wire_creation' && this.wireCreationState?.previewWire) {\n previews.push(this.wireCreationState.previewWire);\n }\n\n return previews;\n }\n\n // ========================================================================\n // Event Handlers\n // ========================================================================\n\n /**\n * Handle pointer down event\n * Routes to appropriate operation based on hover target and state\n */\n private handlePointerDown(event: MouseEvent): void {\n if (event.button !== 0) return; // Only handle left click\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n const hoveredElement = this._controller.getHoveredElement();\n\n if (this.mode === 'idle') {\n // Handle Ctrl+Shift+click for config panel (T011, T012)\n if ((event.ctrlKey || event.metaKey) && event.shiftKey && hoveredElement) {\n if (hoveredElement.type === 'component') {\n this.openConfigPanel(hoveredElement.id, event);\n }\n // Early exit - don't start other operations\n return;\n }\n\n // Handle Ctrl+click for sourceType or fast component config cycling\n if ((event.ctrlKey || event.metaKey) && hoveredElement) {\n if (hoveredElement.type === 'enode') {\n this.cycleEnodeSourceType(hoveredElement.id, hoveredElement.object3D);\n } else if (hoveredElement.type === 'component') {\n this._controller.cycleComponentConfig(hoveredElement.id);\n }\n // TODO: for wire maybe implement a path regularization feature later\n // Early exit - don't start wire creation\n return;\n }\n\n if (hoveredElement && hoveredElement.type === 'enode') {\n const enodeId = hoveredElement.id;\n // special priority 0 : if a wire creation was just cancelled, and we click again on the same enode within 500ms, we start dragging the branching point instead of starting a new wire creation\n const isBranchingPoint = !hoveredElement.object3D.userData.componentId;\n if (\n isBranchingPoint &&\n this.lastCancelledOp &&\n this.lastCancelledOp.mode === 'wire_creation' &&\n Date.now() - this.lastCancelledOp.ts < 500\n ) {\n this.startBPDrag(enodeId, this._controller.cursorGroundPlanePosition());\n return;\n }\n\n // Priority 1 : Check if we're hovering an enode and start wire creation\n this.startWireCreation(enodeId);\n return;\n }\n // Priority 2 : Check if we're hovering a component\n if (hoveredElement && hoveredElement.type === 'component') {\n const componentId = hoveredElement.id;\n this.startComponentDrag(componentId, this._controller.cursorGroundPlanePosition());\n return;\n }\n // Priority 3 : Check if we're hovering a wire\n if (hoveredElement && hoveredElement.type === 'wire') {\n const wireId = hoveredElement.id;\n const screenPos = new THREE.Vector2(event.clientX, event.clientY);\n const worldPosition = this._controller.cursorGroundPlanePosition();\n\n // Drag target resolution: branching point > existing intermediate > new intermediate\n const wire = circuit.getWire(wireId);\n if (!wire) return;\n\n // Priority 3-1: Check for existing intermediate point\n const nearestPoint = this._controller.wireVisualManager.findNearestIntermediatePoint(\n wireId,\n screenPos\n );\n if (nearestPoint) {\n // Start dragging existing intermediate point\n const pos = wire.intermediatePositions[nearestPoint.pointIndex];\n if (pos) {\n const worldPos = new THREE.Vector3(pos.x, 0, -pos.y);\n this.startWireDrag(wireId, 'intermediate', nearestPoint.pointIndex, worldPos);\n return;\n }\n }\n // Priority 3-2: Create new intermediate point at click position\n const insertIndex = this._controller.wireVisualManager.getInsertIndexForPosition(\n wireId,\n worldPosition\n );\n this.startWireDrag(wireId, 'new_intermediate', insertIndex, worldPosition);\n return;\n }\n } else if (this.mode === 'wire_creation') {\n if (!hoveredElement) {\n // Clicked on empty space during wire creation - cancel ?\n // TODO: isn't it the spec to create a branching point here? or handled elsewhere and this branch is unnecessary ?\n this.cancelWireCreation();\n return;\n }\n }\n }\n\n /**\n * Handle pointer up event\n *\n * Ends current operation, commits final positions to the circuit model,\n * and re-enables camera controls.\n *\n * Completes current operation based on mode\n */\n private handlePointerUp(event: MouseEvent): void {\n if (event.button !== 0) return; // Only handle left click\n\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n const hoveredElement = this._controller.getHoveredElement();\n\n if (this.mode === 'wire_creation') {\n // specific case : clicking on source enode cancels the wire creation but may lead to dragging branching point\n if (\n hoveredElement &&\n hoveredElement.type === 'enode' &&\n hoveredElement.id === this.wireCreationState?.sourceEnodeId\n ) {\n this.cancelWireCreation();\n } else {\n this.completeWireCreation(hoveredElement);\n }\n } else if (this.mode === 'wire_drag') {\n // Commit wire drag operation\n this.completeWireDrag();\n } else if (this.mode === 'bp_drag') {\n // Commit branching point drag operation\n this.completeBPDrag();\n } else if (this.mode === 'component_drag') {\n // Commit component drag operation\n this.completeComponentDrag();\n }\n\n // Finally stop listening to gridPositionMove events\n this._controller.off('gridPositionMove', this.handleGridPositionMove);\n // and unlock MapControl change of camera\n this._controller.getControls()!.enablePan = true;\n }\n\n /**\n * Handle grid position move event according to ongoing mode\n * Updates preview or drag position during active operations\n */\n private handleGridPositionMove(position: THREE.Vector3): void {\n switch (this.mode) {\n case 'wire_creation':\n this.updateWireCreation(position);\n break;\n case 'wire_drag':\n this.updateWireDrag(position);\n break;\n case 'component_drag':\n this.updateComponentDrag(position);\n break;\n case 'bp_drag':\n this.updateBPDrag(position);\n break;\n default:\n break;\n }\n }\n\n /**\n * Handle keyboard events\n * Supports Escape (cancel), Delete/Backspace (delete), R (rotate), Ctrl+C (copy), Ctrl+V (paste)\n */\n private handleKeyDown(event: KeyboardEvent): void {\n // cancel ongoing action on Escape\n if (event.key === 'Escape') {\n if (this.mode === 'wire_creation') {\n this.cancelWireCreation();\n } else if (this.mode === 'wire_drag') {\n this.cancelWireDrag();\n } else if (this.mode === 'bp_drag') {\n this.cancelBPDrag();\n } else if (this.mode === 'component_drag') {\n this.cancelComponentDrag();\n }\n return;\n }\n\n // Handle copy (CTRL+C) - copy selected component type and rotation\n if ((event.ctrlKey || event.metaKey) && event.key === 'c') {\n const selection = this._controller.getSelectionManager().getSelection();\n if (selection && selection.kind === 'mono' && selection.type === 'component') {\n this.copyComponent(selection.id);\n }\n return;\n }\n\n // Handle paste (CTRL+V) - paste component at hovered position\n if ((event.ctrlKey || event.metaKey) && event.key === 'v') {\n if (this.clipboard) {\n this.pasteComponent();\n }\n return;\n }\n\n // actions on selection\n const selection = this._controller.getSelectionManager().getSelection();\n if (!selection) return;\n if (selection.kind === 'multi') return; //this tool only handles mono selection for deletion\n const monoSelection = selection as MonoSelectionData;\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n // Handle deletion of components, wires, branching points\n if (monoSelection.type === 'component') {\n const componentId = monoSelection.id;\n this._controller.removeComponent(componentId);\n } else if (monoSelection.type === 'wire') {\n const wireId = monoSelection.id;\n this._controller.removeWire(wireId);\n } else if (monoSelection.type === 'enode' && monoSelection.data === 'BranchingPoint') {\n const enodeId = monoSelection.id;\n this._controller.removeBranchingPoint(enodeId);\n // TODO: may fail if the resulting merged wire is a duplicate - see how to handle this case\n }\n } else if (event.key === 'r' || event.key === 'R') {\n // Handle R key to rotate selected component\n if (monoSelection.type === 'component') {\n const componentId = monoSelection.id;\n this.rotateComponent(componentId);\n }\n }\n }\n\n /**\n * Handle double-click events\n * Routes to rotation (component) or branching point creation (wire/empty)\n */\n private handleDblClick(event: MouseEvent): void {\n if (event.button !== 0) return; // Only handle left click\n\n const hoveredElement = this._controller.getHoveredElement();\n\n // Priority 1 - Check if we're hovering a wire => split it with new branchingPoint\n if (hoveredElement && hoveredElement.type === 'wire') {\n const wireId = hoveredElement.id;\n const gridPosition = this._controller.cursorGroundPlanePosition();\n const enodeId = this.createBranchingPointOnWire(wireId, gridPosition);\n if (enodeId) {\n this._controller.getSelectionManager().selectOne('enode', enodeId, { componentId: null });\n }\n }\n // Priority 2 - Check if we're hovering a component => rotate it\n else if (hoveredElement && hoveredElement.type === 'component') {\n const componentId = hoveredElement.id;\n this.rotateComponent(componentId);\n } else if (!hoveredElement) {\n // Priority 3 - Double-click on empty space - create standalone branching point\n const gridPosition = this._controller.cursorGroundPlanePosition();\n const enodeId = this.createStandaloneBranchingPoint(gridPosition);\n if (enodeId) {\n this._controller.getSelectionManager().selectOne('enode', enodeId, { componentId: null });\n }\n }\n }\n\n /**\n * Operations lifecycle methods\n * (start, update, cancel, complete)\n */\n\n /**\n * Start wire creation from source enode\n * @param sourceEnodeId - Source enode ID\n */\n private startWireCreation(sourceEnodeId: UUID): void {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n const sourceEnode = circuit.getENode(sourceEnodeId);\n if (!sourceEnode) return;\n\n // Get source position\n const enodeGroup = this._controller.enodeObject3Ds.get(sourceEnodeId);\n if (!enodeGroup) return;\n const sourcePosition = enodeGroup.position.clone();\n if (enodeGroup.userData.componentId) {\n // since pins (enodes of components) are children of the component object3D,\n // we need to get the world position\n enodeGroup.getWorldPosition(sourcePosition);\n }\n\n // Create preview wire\n const previewWire = this._controller.wireVisualManager.createPreviewWire(sourcePosition);\n\n // Enter wire creating state\n this.mode = 'wire_creation';\n this.wireCreationState = {\n sourceEnodeId,\n sourcePosition: sourcePosition.clone(),\n previewWire,\n ts: Date.now(),\n };\n\n this._controller.getControls()!.enablePan = false;\n this._controller.on('gridPositionMove', this.handleGridPositionMove);\n\n this._controller.emit('toolOperationStarted', {\n toolType: this.type,\n mode: this.mode,\n operationData: { sourceEnodeId },\n });\n }\n\n /**\n * Update wire creation preview with new target position\n * @param position\n * @private\n */\n private updateWireCreation(position: THREE.Vector3): void {\n this._controller.wireVisualManager.updatePreviewWire(position);\n }\n\n /**\n * Cancel wire creation and reset state\n */\n private cancelWireCreation(emit: boolean = true): void {\n if (this.mode !== 'wire_creation') return;\n this._controller.wireVisualManager.removePreviewWire();\n if (emit) {\n this._controller.emit('toolOperationCancelled', {\n toolType: this.type,\n mode: this.mode,\n });\n }\n this.lastCancelledOp = {\n mode: this.mode,\n ts: Date.now(),\n };\n // Reset state\n this.mode = 'idle';\n this.wireCreationState = null;\n }\n\n /**\n * Complete wire creation between source enode and :\n * - existing target enode if it is hovered\n * - new branching point on wire if target is a wire\n * - new branching point if target is null\n * @param hoveredElement - Currently hovered element at wire creation end\n */\n private completeWireCreation(hoveredElement: HoveredElement | null): UUID | undefined {\n if (this.mode !== 'wire_creation' || !this.wireCreationState) return;\n\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n const sourceEnodeId = this.wireCreationState.sourceEnodeId;\n\n // Saving to model, Validation checks are done in the process\n try {\n let targetEnodeId = null;\n let hasSelected = false;\n if (!hoveredElement) {\n // finishing on empty space : create end branching point\n const worldPosition = this._controller.cursorGroundPlanePosition();\n targetEnodeId = this.createStandaloneBranchingPoint(worldPosition);\n if (targetEnodeId) {\n this._controller\n .getSelectionManager()\n .selectOne('enode', targetEnodeId, { componentId: null });\n hasSelected = true;\n }\n } else if (hoveredElement.type === 'wire') {\n // this interesting case create a new branching point on the wire and connect to it\n const targetWireId = hoveredElement.id;\n const gridPosition = this._controller.cursorGroundPlanePosition();\n targetEnodeId = this.createBranchingPointOnWire(targetWireId, gridPosition);\n } else if (hoveredElement.type === 'enode') {\n targetEnodeId = hoveredElement.id;\n }\n\n if (!targetEnodeId) {\n throw new Error('Invalid target for wire creation');\n }\n\n // Create definitive wire visual\n const wire = this._controller.addWire(sourceEnodeId, targetEnodeId);\n // select the new wire if nothing was selected before\n if (!hasSelected) {\n this._controller.getSelectionManager().selectOne('wire', wire.id);\n }\n // Emit success event\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: this.mode,\n operationData: { wireId: wire.id, sourceEnodeId, targetEnodeId },\n changedData: { addedWires: [wire.id] },\n });\n // Reset state (end preview)\n this.cancelWireCreation();\n return wire.id;\n } catch (error) {\n this.cancelWireCreation();\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: this.mode,\n errorMessage: error instanceof Error ? error.message : 'Unknown error during wire creation',\n });\n }\n // Reset state\n this.mode = 'idle';\n this.wireCreationState = null;\n return;\n }\n\n /**\n * Start wire dragging operation\n * @param wireId - Wire being dragged\n * @param targetType - Type of drag target\n * @param pointIndex - Index of intermediate point, or -1 for new/branching\n * @param worldPosition - Initial position\n */\n private startWireDrag(\n wireId: UUID,\n targetType: 'intermediate' | 'new_intermediate',\n pointIndex: number,\n worldPosition: THREE.Vector3\n ): void {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n const wire = circuit.getWire(wireId);\n if (!wire) return;\n\n // Store original positions for cancellation\n const originalPositions = wire.intermediatePositions.map((p) => ({ ...p }));\n\n // If creating new intermediate point, insert it now\n if (targetType === 'new_intermediate') {\n const insertIndex = pointIndex;\n const gridPos = worldToGridPosition(worldPosition);\n originalPositions.splice(insertIndex, 0, gridPos);\n pointIndex = insertIndex;\n }\n\n this.mode = 'wire_drag';\n this.wireDragState = {\n wireId,\n pointIndex,\n initialPosition: worldPosition.clone(),\n originalPositions,\n targetType,\n };\n\n // block MapControls panning and register for gridPositionMove events\n this._controller.getControls()!.enablePan = false;\n this._controller.on('gridPositionMove', this.handleGridPositionMove);\n\n this._controller.emit('toolOperationStarted', {\n toolType: this.type,\n mode: this.mode,\n operationData: { wireId, pointIndex, targetType },\n });\n }\n\n /**\n * Update drag target position during drag\n * @param worldPosition - Current cursor position in world space\n */\n private updateWireDrag(worldPosition: THREE.Vector3): void {\n if (this.mode !== 'wire_drag' || !this.wireDragState) return;\n\n // Update intermediate positions array\n const gridPos = worldToGridPosition(worldPosition);\n const newPositions = [...this.wireDragState.originalPositions];\n newPositions[this.wireDragState.pointIndex] = gridPos;\n\n // T063: Real-time geometry update with temporary positions\n // Use circuit's update method to set intermediate positions\n this._controller.circuitWriter.saveEditWirePositions(this.wireDragState.wireId, newPositions);\n this._controller.wireVisualManager.updateWireById(this.wireDragState.wireId);\n }\n\n /**\n * Cancel wire drag operation and revert to original positions\n */\n private cancelWireDrag(emit: boolean = true): void {\n if (this.mode !== 'wire_drag' || !this.wireDragState) return;\n\n // Revert intermediate positions\n this._controller.circuitWriter.saveEditWirePositions(\n this.wireDragState.wireId,\n this.wireDragState.originalPositions,\n true\n );\n this._controller.wireVisualManager.updateWireById(this.wireDragState.wireId);\n\n if (emit) {\n this._controller.emit('toolOperationCancelled', {\n toolType: this.type,\n mode: this.mode,\n });\n }\n this.lastCancelledOp = {\n mode: this.mode,\n ts: Date.now(),\n };\n // Reset state\n this.mode = 'idle';\n this.wireDragState = null;\n }\n\n /**\n * Commit drag operation and persist changes\n */\n private completeWireDrag(): void {\n if (this.mode !== 'wire_drag' || !this.wireDragState) return;\n\n const wireDragState = this.wireDragState;\n // Reset state\n this.mode = 'idle';\n this.wireDragState = null;\n\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n const wireId = wireDragState.wireId;\n const wire = circuit.getWire(wireId);\n if (!wire) return;\n\n try {\n //Check for merge/delete conditions\n const finalPositions = this.checkMergeDelete(wire);\n // Persist to model via CircuitWriter\n this._controller.circuitWriter.saveEditWirePositions(\n wireDragState.wireId,\n finalPositions,\n true\n );\n\n const hoveredElement = this._controller.getHoveredElement();\n // special case 1 : if wire was dragged to enode, we need to split it and connect to it\n if (hoveredElement && hoveredElement.type === 'enode') {\n const targetEnodeId = hoveredElement.id;\n const worldPosition = this._controller.cursorGroundPlanePosition();\n const result = this._controller.splitWire(wireId, worldPosition, targetEnodeId);\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: this.mode,\n operationData: {\n wireId: wireId,\n intermediatePositions: finalPositions,\n targetEnodeId: targetEnodeId,\n },\n changedData: {\n removedWire: wireId,\n enodeId: result.branchingPoint.id,\n addedWires: result.wires.map((w) => w.id),\n },\n });\n this._controller\n .getSelectionManager()\n .selectOne('enode', targetEnodeId, { componentId: null });\n return;\n }\n // special case 2 : if wire was dragged to ANOTHER wire, we split that wire with a branching point,\n // then split our dragged wire to connect to that branching point\n if (hoveredElement && hoveredElement.type === 'wire' && hoveredElement.id !== wireId) {\n const targetWireId = hoveredElement.id;\n const worldPosition = this._controller.cursorGroundPlanePosition();\n const targetEnodeId = this.createBranchingPointOnWire(targetWireId, worldPosition);\n const result = this._controller.splitWire(wireId, worldPosition, targetEnodeId);\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: this.mode,\n operationData: {\n wireId: wireId,\n intermediatePositions: finalPositions,\n targetWireId: targetWireId,\n },\n changedData: {\n removedWire: wireId,\n enodeId: result.branchingPoint.id,\n addedWires: result.wires.map((w) => w.id),\n },\n });\n if (targetEnodeId) {\n this._controller\n .getSelectionManager()\n .selectOne('enode', targetEnodeId, { componentId: null });\n }\n return;\n }\n\n // Default case : Update visual\n this._controller.wireVisualManager.updateWireById(wireDragState.wireId);\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: this.mode,\n operationData: {\n wireId: wireId,\n intermediatePositions: finalPositions,\n },\n changedData: {\n updatedWires: [wireId],\n },\n });\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: this.mode,\n errorMessage: `Failed to commit wire drag: ${(error as Error).message}`,\n });\n this.cancelWireDrag(false);\n }\n }\n\n /**\n * Start component dragging operation\n * @param componentId - UUID of the component being dragged\n * @param worldPosition - Initial position\n */\n private startComponentDrag(componentId: UUID, worldPosition: THREE.Vector3): void {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n const component = circuit.getComponent(componentId);\n if (!component) return;\n\n this.mode = 'component_drag';\n this.componentDragState = {\n componentId,\n initialPosition: worldPosition.clone(),\n };\n\n // block MapControls panning and register for gridPositionMove events\n this._controller.getControls()!.enablePan = false;\n this._controller.on('gridPositionMove', this.handleGridPositionMove);\n\n this._controller.emit('toolOperationStarted', {\n toolType: this.type,\n mode: this.mode,\n operationData: { componentId },\n });\n }\n\n /**\n * Update component visual position during drag\n * @param worldPosition - Current cursor position in world space\n */\n private updateComponentDrag(worldPosition: THREE.Vector3): void {\n if (this.mode !== 'component_drag' || !this.componentDragState) return;\n\n const object = this._controller.getObject3D('component', this.componentDragState.componentId);\n if (!object) return;\n\n const newPosition = nearestWorldSnapPosition(worldPosition);\n object.position.copy(newPosition);\n\n // moving wires connected to component in real-time during drag\n this._controller.wireVisualManager.updateWiresForComponent(this.componentDragState.componentId);\n }\n\n /**\n * Cancel component drag operation and revert to original positions\n */\n private cancelComponentDrag(emit: boolean = true): void {\n if (this.mode !== 'component_drag' || !this.componentDragState) return;\n\n // restore original component visual\n const object = this._controller.getObject3D('component', this.componentDragState.componentId);\n if (!object) return;\n\n object.position.copy(this.componentDragState.initialPosition);\n // restore wires connected to component\n this._controller.wireVisualManager.updateWiresForComponent(this.componentDragState.componentId);\n\n if (emit) {\n this._controller.emit('toolOperationCancelled', {\n toolType: this.type,\n mode: 'component_drag',\n });\n }\n this.lastCancelledOp = {\n mode: this.mode,\n ts: Date.now(),\n };\n // Reset state\n this.mode = 'idle';\n this.componentDragState = null;\n }\n\n /**\n * complete component drag operation and persist changes\n */\n private completeComponentDrag(): void {\n if (this.mode !== 'component_drag' || !this.componentDragState) return;\n\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n const componentId = this.componentDragState.componentId;\n const object = this._controller.getObject3D('component', componentId);\n if (!object) return;\n\n try {\n const component = this._controller.circuitWriter.saveEditComponent(componentId, object, true);\n for (const connectedWire of circuit.getWiresByComponent(componentId)) {\n this._controller.circuitWriter.saveSimplifyWirePositions(connectedWire.id);\n this._controller.wireVisualManager.updateWireById(connectedWire.id);\n }\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'component_drag',\n operationData: {\n componentId: componentId,\n newPosition: component.position,\n },\n changedData: {},\n });\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: this.mode,\n errorMessage: `Failed to commit component drag: ${(error as Error).message}`,\n });\n this.cancelComponentDrag(false);\n }\n\n // Reset state\n this.mode = 'idle';\n this.componentDragState = null;\n }\n\n /**\n * Start branching point dragging operation\n * @param enodeId - UUID of the branching point being dragged\n * @param worldPosition - Initial position\n */\n private startBPDrag(enodeId: UUID, worldPosition: THREE.Vector3): void {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n const branchingPoint = circuit.getENode(enodeId);\n if (!branchingPoint) return;\n\n this.mode = 'bp_drag';\n this.bpDragState = {\n enodeId,\n initialPosition: worldPosition.clone(),\n };\n // block MapControls panning and register for gridPositionMove events\n this._controller.getControls()!.enablePan = false;\n this._controller.on('gridPositionMove', this.handleGridPositionMove);\n\n this._controller.emit('toolOperationStarted', {\n toolType: this.type,\n mode: this.mode,\n operationData: { enodeId },\n });\n }\n\n /**\n * Update branching point position during drag\n * @param worldPosition - Current cursor position in world space\n */\n private updateBPDrag(worldPosition: THREE.Vector3): void {\n if (this.mode !== 'bp_drag' || !this.bpDragState) return;\n\n const visual = this._controller.enodeObject3Ds.get(this.bpDragState.enodeId);\n if (!visual) return;\n\n visual.position.copy(nearestWorldSnapPosition(worldPosition));\n const enode = this._controller.circuitWriter.saveEditBranchingPoint(visual);\n\n // Update all wires connected to this branching point\n for (const connectedWireId of enode.wires) {\n this._controller.wireVisualManager.updateWireById(connectedWireId);\n }\n }\n\n /**\n * Cancel branching point drag operation and revert to original positions\n */\n private cancelBPDrag(emit: boolean = true): void {\n if (this.mode !== 'bp_drag' || !this.bpDragState) return;\n\n const initialPosition = this.bpDragState.initialPosition;\n // Update bp visual\n const visual = this._controller.enodeObject3Ds.get(this.bpDragState.enodeId);\n if (!visual) return;\n visual.position.copy(initialPosition);\n\n const enode = this._controller.circuitWriter.saveEditBranchingPoint(visual);\n\n // restore all wires connected to this branching point\n for (const connectedWireId of enode.wires) {\n this._controller.wireVisualManager.updateWireById(connectedWireId);\n }\n\n if (emit) {\n this._controller.emit('toolOperationCancelled', {\n toolType: this.type,\n mode: 'bp_drag',\n });\n }\n this.lastCancelledOp = {\n mode: this.mode,\n ts: Date.now(),\n };\n // Reset state\n this.mode = 'idle';\n this.bpDragState = null;\n }\n\n /**\n * Commit branching point drag operation and persist changes\n */\n private completeBPDrag(): void {\n if (this.mode !== 'bp_drag' || !this.bpDragState) return;\n\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n try {\n const branchingPoint = circuit.getENode(this.bpDragState.enodeId);\n if (!branchingPoint) {\n throw new Error(`Branching point ${this.bpDragState.enodeId} not found`);\n }\n // Branching point drag position is already updated, but it's a good place to simplify wire path if necessary\n for (const connectedWireId of branchingPoint.wires) {\n this._controller.circuitWriter.saveSimplifyWirePositions(connectedWireId);\n this._controller.wireVisualManager.updateWireById(connectedWireId);\n }\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'bp_drag',\n operationData: {\n branchingPointId: this.bpDragState.enodeId,\n newPosition: branchingPoint.position,\n },\n changedData: {},\n });\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: this.mode,\n errorMessage: `Failed to commit branching point drag: ${(error as Error).message}`,\n });\n this.cancelBPDrag(false);\n return;\n }\n // Reset state\n this.mode = 'idle';\n this.bpDragState = null;\n }\n\n /**\n * private helpers\n */\n\n /**\n * Create a standalone branching point at empty grid position (T048)\n * @param worldPosition - 3D position in world space\n */\n private createStandaloneBranchingPoint(worldPosition: THREE.Vector3): UUID | undefined {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n try {\n // Create branching point in circuit model (no sourceType initially)\n const branchingPoint = this._controller.addBranchingPoint(worldPosition);\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'bp_creation',\n operationData: {\n worldPosition,\n },\n changedData: {\n enodeId: branchingPoint.id,\n },\n });\n return branchingPoint.id;\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: 'bp_creation',\n errorMessage: `Failed to create branching point: ${(error as Error).message}`,\n });\n }\n return;\n }\n\n /**\n * Create a branching point on an existing wire, splitting it (T044)\n * @param wireId - Wire to split\n * @param worldPosition - 3D position in world space\n */\n private createBranchingPointOnWire(wireId: UUID, worldPosition: THREE.Vector3): UUID | undefined {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n try {\n const result = this._controller.splitWire(wireId, worldPosition);\n // Emit success event\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'bp_creation',\n operationData: {\n wireId,\n worldPosition,\n },\n changedData: {\n removedWire: wireId,\n enodeId: result.branchingPoint.id,\n addedWires: result.wires.map((w) => w.id),\n },\n });\n return result.branchingPoint.id;\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: 'bp_creation',\n errorMessage: `Failed to create branching point: ${(error as Error).message}`,\n });\n return;\n }\n }\n\n /**\n * Check if hoveredElement is a valid wire target during wire creation\n * @param hoveredElement - Current hovered element or null\n * @returns True if target is valid for wire endpoint\n */\n private isValidWireTarget(hoveredElement: { type: HoverableType; id: UUID } | null): boolean {\n if (!this.wireCreationState) return false;\n\n if (!hoveredElement) return true; // Empty space is valid (creates BP)\n\n // Enode is valid unless it's the source\n if (hoveredElement.type === 'enode') {\n return hoveredElement.id !== this.wireCreationState.sourceEnodeId;\n }\n\n // Wire is valid (creates BP on wire)\n if (hoveredElement.type === 'wire') {\n return true;\n }\n\n // Component is not a valid target\n return false;\n }\n\n /**\n * Rotate a component 90° clockwise\n *\n * Updates both the circuit model and visual representation.\n * Emits componentRotated event to notify listeners.\n * Only works on selected components (not wires or enodes).\n */\n private rotateComponent(componentId: UUID): void {\n const object = this._controller.getObject3D('component', componentId);\n if (!object) {\n return;\n }\n const currentAngle = object.rotation.y;\n const newAngle = (currentAngle - Math.PI / 2) % (Math.PI * 2);\n object.rotation.set(0, newAngle, 0);\n\n try {\n const component = this._controller.circuitWriter.saveEditComponent(componentId, object);\n this._controller.wireVisualManager.updateWiresForComponent(component.id);\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'component_rotate',\n operationData: {\n componentId: componentId,\n newPosition: component.position,\n },\n changedData: {},\n });\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: this.mode,\n errorMessage: `Failed to commit component rotate: ${(error as Error).message}`,\n });\n this.cancelComponentDrag(false);\n }\n }\n\n /**\n * Check if wire intermediate point should be merged or deleted\n * Returns updated positions array after merge/delete check\n * @param wire - Wire being modified\n * @returns Final intermediate positions array\n */\n private checkMergeDelete(wire: any): { x: number; y: number }[] {\n if (!this.wireDragState) return wire.intermediatePositions;\n\n const positions = [...wire.intermediatePositions];\n // handle no intermediate positions\n if (positions.length === 0) return positions;\n const draggedIndex = this.wireDragState.pointIndex;\n const draggedPos = positions[draggedIndex];\n\n // Check if dragged point is very close to wire endpoints or other intermediate points\n const circuit = this._controller.getCircuit();\n if (!circuit) return positions;\n\n const node1 = circuit.getENode(wire.node1);\n const node2 = circuit.getENode(wire.node2);\n if (!node1 || !node2) return positions;\n\n const endpoint1 = node1.getPosition(circuit);\n const endpoint2 = node2.getPosition(circuit);\n\n const threshold = 0.5; // Grid units\n\n // Check if close to endpoint1\n const distToEndpoint1 = Math.sqrt(\n Math.pow(draggedPos.x - endpoint1.x, 2) + Math.pow(draggedPos.y - endpoint1.y, 2)\n );\n if (distToEndpoint1 < threshold) {\n // Remove this point\n positions.splice(draggedIndex, 1);\n return positions;\n }\n\n // Check if close to endpoint2\n const distToEndpoint2 = Math.sqrt(\n Math.pow(draggedPos.x - endpoint2.x, 2) + Math.pow(draggedPos.y - endpoint2.y, 2)\n );\n if (distToEndpoint2 < threshold) {\n // Remove this point\n positions.splice(draggedIndex, 1);\n return positions;\n }\n\n // Check if close to other intermediate points\n for (let i = 0; i < positions.length; i++) {\n if (i === draggedIndex) continue;\n\n const otherPos = positions[i];\n const dist = Math.sqrt(\n Math.pow(draggedPos.x - otherPos.x, 2) + Math.pow(draggedPos.y - otherPos.y, 2)\n );\n\n if (dist < threshold) {\n // Merge: remove the dragged point\n positions.splice(draggedIndex, 1);\n return positions;\n }\n }\n\n return positions;\n }\n\n /**\n * Copy component type and rotation to clipboard\n * @param componentId - UUID of the component to copy\n */\n private copyComponent(componentId: UUID): void {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n const component = circuit.getComponent(componentId);\n if (!component) return;\n\n const sources = component.pins.map((pinId) => {\n const enode = circuit.getENode(pinId);\n return enode ? enode.source : null;\n });\n\n this.clipboard = {\n componentType: component.type,\n rotation: gridToWorldRotation(component.rotation),\n pinSources: sources,\n config: new Map(component.config), // Deep copy of config\n };\n }\n\n /**\n * Paste component from clipboard at hovered position\n * Creates a new component with the type and rotation from clipboard\n */\n private pasteComponent(): void {\n if (!this.clipboard) return;\n\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n\n // Get cursor position\n const worldPosition = this._controller.cursorGroundPlanePosition();\n\n this._controller.addComponent(\n this.clipboard.componentType,\n worldPosition,\n this.clipboard.rotation,\n this.clipboard.config,\n this.clipboard.pinSources\n );\n }\n\n /**\n * Cycles the sourceType of an enode: null → Voltage → Current → null\n * Updates both model and visual immediately.\n * @param enodeId - UUID of the enode to cycle\n * @param hitbox - hitbox of the enode being clicked\n */\n private cycleEnodeSourceType(enodeId: UUID, hitbox: THREE.Object3D): void {\n if (hitbox.userData.lockedSourceType) return; // do not update locked source types\n if (!hitbox.parent) return;\n\n const nextSourceType = getNextSourceType(hitbox.parent.userData.sourceType);\n this._controller.updateEnodeSourceType(enodeId, nextSourceType || null);\n }\n\n /**\n * Open config panel for component (T014)\n * Converts component world position to screen coordinates and opens panel\n * @param componentId - UUID of the component to configure\n * @param event - Mouse event for screen position\n */\n private openConfigPanel(componentId: UUID, event: MouseEvent): void {\n const screenPosition = { x: event.clientX, y: event.clientY };\n this._controller.openConfigPanel(componentId, screenPosition);\n }\n}\n","/**\n * Place Component Tool Implementation\n * @module scene/static/tools/AddComponentTool\n *\n * Tool for adding new components to the circuit with visual preview and validation.\n * User Story 1 (P1 - MVP): Select component type and place on canvas\n * - Hover shows ghost preview at cursor position\n * - Click to place component at preview position\n * - Grid snapping for precise placement\n */\n\nimport * as THREE from 'three';\nimport { Euler } from 'three';\nimport type { ComponentType } from 'simple-circuit-engine/core';\nimport { Position, Rotation, Component } from 'simple-circuit-engine/core';\n\n\nimport type { IEditingTool, ToolType, CursorType } from '../../shared/types';\nimport type { CircuitController } from '../CircuitController';\n\n/**\n * Tool for adding new components to the circuit\n * Provides ghost preview, grid snapping, and placement validation\n */\nexport class AddComponentTool implements IEditingTool {\n readonly type: ToolType = 'addComponent';\n\n private _controller: CircuitController;\n private _componentType: ComponentType | null = null;\n private _ghostPreview: THREE.Group | null = null;\n private _previewPosition: THREE.Vector3 = new THREE.Vector3();\n private _previewRotation: number = 0;\n private _hasOverlap: boolean = false;\n\n // Event handlers stored for cleanup\n private _gridPositionMoveHandler: ((position: THREE.Vector3) => void) | null = null;\n private _pointerDownHandler: ((event: MouseEvent) => void) | null = null;\n private _wheelHandler: ((event: WheelEvent) => void) | null = null;\n private _keyDownHandler: ((event: KeyboardEvent) => void) | null = null;\n\n constructor(controller: CircuitController) {\n this._controller = controller;\n }\n\n /**\n * Called when tool becomes active (T010)\n * Attaches event listeners for hover and click interactions\n */\n onActivate(): void {\n this._previewRotation = 0;\n this._hasOverlap = false;\n\n // Attach gridPositionMove listener for hover preview updates\n this._gridPositionMoveHandler = (position: THREE.Vector3) => {\n this.handleGridPositionMove(position);\n };\n this._controller.on('gridPositionMove', this._gridPositionMoveHandler);\n\n // Attach pointerdown listener for placement\n this._pointerDownHandler = (event: MouseEvent) => {\n if (event.button === 0) {\n // Left click only\n this.handlePointerDown(this._previewPosition);\n }\n };\n this._controller.getContainer().addEventListener('pointerdown', this._pointerDownHandler);\n\n // Attach wheel listener for rotation (User Story 3 - will be used in Phase 5)\n this._wheelHandler = (event: WheelEvent) => {\n event.preventDefault();\n this.handleScroll(event.deltaY, event.ctrlKey);\n };\n this._controller.getContainer().addEventListener('wheel', this._wheelHandler, {\n passive: false,\n });\n\n // Attach keydown listener for deletion (User Story 4 - T040)\n this._keyDownHandler = (event: KeyboardEvent) => {\n this.handleKeyDown(event);\n };\n window.addEventListener('keydown', this._keyDownHandler);\n\n // Create initial preview if component type is already set\n if (this._componentType) {\n this._createGhostPreview();\n // deactivating pan and zoom controls while placing components\n this._controller.getControls()!.enablePan = false;\n this._controller.getControls()!.enableZoom = false;\n }\n }\n\n /**\n * Called when tool is deactivated (T011)\n * Removes event listeners and cleans up preview objects\n */\n onDeactivate(): void {\n // Remove event listeners\n if (this._gridPositionMoveHandler) {\n this._controller.off('gridPositionMove', this._gridPositionMoveHandler);\n this._gridPositionMoveHandler = null;\n }\n\n if (this._pointerDownHandler) {\n this._controller.getContainer().removeEventListener('pointerdown', this._pointerDownHandler);\n this._pointerDownHandler = null;\n }\n\n if (this._wheelHandler) {\n this._controller.getContainer().removeEventListener('wheel', this._wheelHandler);\n this._wheelHandler = null;\n }\n\n // Remove keydown listener (User Story 4 - T041)\n if (this._keyDownHandler) {\n window.removeEventListener('keydown', this._keyDownHandler);\n this._keyDownHandler = null;\n }\n\n // Cleanup preview\n this._disposeGhostPreview();\n this._componentType = null;\n this._previewRotation = 0;\n this._hasOverlap = false;\n\n // reactivating pan and zoom controls\n this._controller.getControls()!.enablePan = true;\n this._controller.getControls()!.enableZoom = true;\n }\n\n /**\n * Set the component type to place (T012)\n * Creates a new ghost preview for the selected component type\n *\n * @param type - Component type to place\n */\n setComponentType(type: ComponentType | null): void {\n if (this._componentType === type) return; // No change\n\n this._componentType = type;\n\n // Recreate ghost preview with new component type\n this._disposeGhostPreview();\n\n if (!!this._componentType) {\n this._createGhostPreview();\n // deactivating pan and zoom controls while placing components\n this._controller.getControls()!.enablePan = false;\n this._controller.getControls()!.enableZoom = false;\n } else {\n this._controller.getControls()!.enablePan = true;\n this._controller.getControls()!.enableZoom = true;\n }\n this._controller.emit('addComponentTypeChanged', {\n componentType: this._componentType,\n });\n }\n\n /**\n * Cycle through available component types (for ctrl+scroll)\n * @param forward\n * @private\n */\n private cycleComponentTypes(forward: boolean): void {\n const registry = this._controller.factoryRegistry;\n const types = ['none', ...Array.from(registry.getRegisteredTypes())];\n if (types.length < 2) return;\n\n let currentIndex = types.indexOf(this._componentType || 'none');\n if (currentIndex < 0) return;\n\n currentIndex = (currentIndex + (forward ? 1 : -1) + types.length) % types.length;\n\n const newType = types[currentIndex] === 'none' ? null : (types[currentIndex] as ComponentType);\n this.setComponentType(newType);\n }\n\n /**\n * Create ghost preview for the current component type (T013)\n * Uses FactoryRegistry to create visual representation\n * @private\n */\n private _createGhostPreview(): void {\n if (!this._componentType) {\n return;\n }\n\n try {\n const factory = this._controller.factoryRegistry.get(this._componentType);\n\n // Create a temporary component for preview (won't be added to circuit yet)\n const tempComponent = new Component(\n this._componentType,\n new Position(0, 0),\n new Rotation(0),\n [] // Empty pins array for preview\n );\n\n // Create visual using factory\n const visual = factory.createVisual(tempComponent);\n\n // Type check: ensure we got a Group object\n if (!(visual instanceof THREE.Group)) {\n console.warn(`Factory returned non-Group object for ${this._componentType}`);\n this._ghostPreview = null;\n return;\n }\n visual.userData.preview = true; // Mark as preview objects\n visual.traverse((child) => {\n child.userData.preview = true;\n });\n\n this._ghostPreview = visual;\n\n // Apply ghost effect (T014)\n this._applyGhostEffect(this._ghostPreview);\n\n // Set initial position\n this._ghostPreview.position.copy(this._previewPosition);\n\n // Apply initial rotation\n this._ghostPreview.rotation.y = (this._previewRotation * Math.PI) / 180;\n\n // add to the scene\n this._controller.getScene().add(this._ghostPreview);\n } catch (error) {\n console.warn(`Failed to create ghost preview for ${this._componentType}:`, error);\n this._ghostPreview = null;\n }\n }\n\n /**\n * Apply ghost effect to preview object (T014)\n * Makes the preview semi-transparent to indicate it's not yet placed\n *\n * @param object - Object3D to apply ghost effect to\n * @private\n */\n private _applyGhostEffect(object: THREE.Object3D): void {\n object.traverse((child) => {\n if (child instanceof THREE.Mesh) {\n // Clone material to avoid affecting placed components (T046 - polish phase)\n if (Array.isArray(child.material)) {\n child.material = child.material.map((mat: THREE.Material) => mat.clone());\n child.material.forEach((mat: THREE.Material) => {\n mat.transparent = true;\n mat.opacity = 0.5;\n });\n } else {\n child.material = child.material.clone();\n child.material.transparent = true;\n child.material.opacity = 0.5;\n }\n }\n });\n }\n\n /**\n * Dispose ghost preview and cleanup resources\n * @private\n */\n private _disposeGhostPreview(): void {\n if (this._ghostPreview) {\n // remove from the scene\n this._controller.getScene().remove(this._ghostPreview);\n // Dispose materials and geometry\n this._ghostPreview.traverse((child) => {\n if (child instanceof THREE.Mesh) {\n if (child.geometry) {\n child.geometry.dispose();\n }\n if (Array.isArray(child.material)) {\n child.material.forEach((mat) => mat.dispose());\n } else {\n child.material.dispose();\n }\n }\n });\n this._ghostPreview = null;\n }\n }\n\n /**\n * Get preview objects to render in the scene (T015)\n * Returns the ghost preview if available\n *\n * @returns Array containing ghost preview object\n */\n getPreviewObjects(): THREE.Object3D[] {\n if (this._ghostPreview && this._componentType) {\n return [this._ghostPreview];\n }\n return [];\n }\n\n /**\n * Check if preview overlaps with existing components (T021)\n * Uses THREE.Box3 bounding box collision detection\n *\n * @returns true if overlap detected, false otherwise\n * @private\n */\n private _checkOverlap(): boolean {\n if (!this._ghostPreview) {\n return false;\n }\n\n // Create bounding box for ghost preview\n const previewBox = new THREE.Box3().setFromObject(this._ghostPreview);\n\n // Get all placed components\n const componentObjects = this._controller.componentObject3Ds;\n\n // Check each component for overlap\n for (const [_id, componentGroup] of componentObjects) {\n const componentBox = new THREE.Box3().setFromObject(componentGroup);\n\n // Check intersection\n if (previewBox.intersectsBox(componentBox)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Apply invalid placement visual effect (T022)\n * Sets red emissive color to indicate invalid placement\n *\n * @param object - Object3D to apply effect to\n * @private\n */\n private _applyInvalidEffect(object: THREE.Object3D): void {\n object.traverse((child) => {\n if (child instanceof THREE.Mesh && child.material) {\n if (Array.isArray(child.material)) {\n child.material.forEach((mat: THREE.Material) => {\n if (mat instanceof THREE.MeshStandardMaterial) {\n mat.emissive.setHex(0xff0000);\n mat.emissiveIntensity = 0.5;\n }\n });\n } else {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n child.material.emissive.setHex(0xff0000);\n child.material.emissiveIntensity = 0.5;\n }\n }\n }\n });\n }\n\n /**\n * Remove invalid placement visual effect (T023)\n * Restores normal emissive values\n *\n * @param object - Object3D to restore\n * @private\n */\n private _removeInvalidEffect(object: THREE.Object3D): void {\n object.traverse((child) => {\n if (child instanceof THREE.Mesh && child.material) {\n if (Array.isArray(child.material)) {\n child.material.forEach((mat: THREE.Material) => {\n if (mat instanceof THREE.MeshStandardMaterial) {\n mat.emissive.setHex(0x000000);\n mat.emissiveIntensity = 0;\n }\n });\n } else {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n child.material.emissive.setHex(0x000000);\n child.material.emissiveIntensity = 0;\n }\n }\n }\n });\n }\n\n /**\n * Handle gridPosition move events (T016, T024)\n * Updates preview position with grid snapping and checks for overlap\n *\n * @param worldPosition - Current cursor position in world coordinates (already grid-snapped)\n */\n handleGridPositionMove(worldPosition: THREE.Vector3): void {\n // Update preview position as grid-snapped current world position\n this._previewPosition.set(Math.round(worldPosition.x), 0, Math.round(worldPosition.z));\n\n // Update ghost preview position if it exists\n if (this._ghostPreview) {\n this._ghostPreview.position.copy(this._previewPosition);\n\n // Check for overlap (T024)\n const previousOverlap = this._hasOverlap;\n this._hasOverlap = this._checkOverlap();\n\n // Apply or remove invalid effect based on overlap state\n if (this._hasOverlap && !previousOverlap) {\n // Just detected overlap\n this._applyInvalidEffect(this._ghostPreview);\n } else if (!this._hasOverlap && previousOverlap) {\n // Overlap cleared\n this._removeInvalidEffect(this._ghostPreview);\n }\n } else {\n this._hasOverlap = false;\n }\n }\n\n /**\n * Handle pointer down events for component placement or selection (T017, T019, T026, T027, T042)\n * - If clicking on existing component: select it\n * - If clicking empty space: place component at preview position\n *\n * @param worldPosition - Click position in world coordinates\n */\n handlePointerDown(worldPosition: THREE.Vector3): void {\n // T042: Check if clicking on an existing component\n const hoveredElement = this._controller.getHoveredElement();\n if (hoveredElement && hoveredElement.type === 'component') {\n // Select the component instead of placing\n this._controller\n .getSelectionManager()\n .selectOne(hoveredElement.type, hoveredElement.id, hoveredElement.object3D.userData);\n return;\n }\n\n // Nothing more to do is no component type is set\n if (!this._componentType) return;\n\n // Check for overlap before placing (T026, T027)\n if (this._hasOverlap) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: 'default',\n errorMessage: 'Cannot place component: position occupied',\n });\n return;\n }\n\n try {\n // Convert preview rotation to Euler\n const rotation = new Euler(0, (this._previewRotation * Math.PI) / 180, 0);\n\n // Place component via CircuitController\n const component = this._controller.addComponent(this._componentType, worldPosition, rotation);\n\n // Emit success event (T019)\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'default',\n operationData: {\n componentId: component.id,\n componentType: this._componentType,\n position: worldPosition.clone(),\n rotation: this._previewRotation,\n },\n changedData: {\n addedComponents: [component.id],\n },\n });\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: 'default',\n errorMessage: `Failed to place component: ${(error as Error).message}`,\n });\n }\n }\n\n /**\n * Handle scroll events for rotation (User Story 3 - Phase 5)\n * Rotates preview by 90 degrees per scroll\n *\n * @param delta - Scroll delta (positive = scroll down, negative = scroll up)\n * @param ctrlKey\n */\n handleScroll(delta: number, ctrlKey: boolean): void {\n if (ctrlKey) {\n // Cycle through component types while ctrl is held\n this.cycleComponentTypes(delta > 0);\n this._controller.getControls()!.enablePan = false;\n this._controller.getControls()!.enableZoom = false;\n return;\n }\n\n // Rotate preview by 90 degrees\n this._previewRotation += delta > 0 ? 90 : -90;\n\n // Normalize to 0-360 range\n this._previewRotation = ((this._previewRotation % 360) + 360) % 360;\n\n // Update ghost preview rotation if it exists\n if (this._ghostPreview) {\n this._ghostPreview.rotation.y = (this._previewRotation * Math.PI) / 180;\n // Check for overlap (T024)\n const previousOverlap = this._hasOverlap;\n this._hasOverlap = this._checkOverlap();\n\n // Apply or remove invalid effect based on overlap state\n if (this._hasOverlap && !previousOverlap) {\n // Just detected overlap\n this._applyInvalidEffect(this._ghostPreview);\n } else if (!this._hasOverlap && previousOverlap) {\n // Overlap cleared\n this._removeInvalidEffect(this._ghostPreview);\n }\n } else {\n this._hasOverlap = false;\n }\n }\n\n /**\n * Handle keyboard events for component deletion (T035-T039)\n * Deletes selected component when Delete or Backspace key is pressed\n *\n * @param event - Keyboard event\n */\n handleKeyDown(event: KeyboardEvent): void {\n // T036: Get current selection from SelectionManager\n const selection = this._controller.getSelectionManager().getSelection();\n\n // echap to set componentType to null\n if (event.key === 'Escape') {\n this.setComponentType(null);\n return;\n }\n\n // Check if Delete or Backspace key pressed and a component is selected\n if (\n (event.key === 'Delete' || event.key === 'Backspace') &&\n selection?.kind === 'mono' &&\n selection.type === 'component'\n ) {\n event.preventDefault();\n event.stopPropagation();\n\n const componentId = selection.id;\n\n try {\n // T037: Call removeComponent() on CircuitController\n this._controller.removeComponent(componentId);\n\n // T038: Clear selection after deletion\n this._controller.getSelectionManager().deselect();\n\n // T039: Emit toolOperationCompleted event with action:'delete'\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'delete',\n operationData: {\n componentId: componentId,\n },\n changedData: {\n removedComponents: [componentId],\n },\n });\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: 'delete',\n errorMessage: `Failed to delete component: ${(error as Error).message}`,\n });\n }\n }\n }\n\n /**\n * Get current cursor type based on tool state (T018, T043)\n * Returns cursor based on hover state:\n * - 'pointer' when hovering existing component\n * - 'not-allowed' when hovering over occupied space for placement\n * - 'crosshair' otherwise\n *\n * @returns Current cursor style\n */\n getCursorType(): CursorType {\n // T043: Return 'pointer' when hovering existing component\n const hoveredElement = this._controller.getHoveredElement();\n if (hoveredElement && hoveredElement.type === 'component') {\n return 'pointer';\n }\n\n // User Story 2 - Return 'not-allowed' when overlap detected\n return this._hasOverlap ? 'not-allowed' : 'crosshair';\n }\n}\n","/**\n * MultiSelectTool - Enables multi-element selection and bulk operations\n * @module scene/static/tools/MultiSelectTool\n */\n\nimport * as THREE from 'three';\nimport type { UUID, ComponentType, ENodeSourceType } from 'simple-circuit-engine/core';\nimport { Position, Rotation } from 'simple-circuit-engine/core';\n\nimport type { IEditingTool, CursorType } from '../../shared/types';\nimport type { CircuitController } from '../CircuitController';\n\nimport {\n gridToWorldPosition,\n gridToWorldRotation,\n isPointInScreenRect,\n nearestWorldSnapPosition,\n worldToGridPosition,\n} from '../../shared/utils/GeometryUtils';\n\n/**\n * Operating modes for the MultiSelectTool\n */\nexport type MultiSelectToolMode = 'idle' | 'selecting' | 'dragging';\n\n/**\n * State during rectangle selection operation (T010)\n */\nexport interface SelectionRectState {\n /** Starting mouse position in screen coordinates */\n startScreen: { x: number; y: number };\n /** Current mouse position in screen coordinates */\n currentScreen: { x: number; y: number };\n /** DOM element for visual rectangle overlay */\n overlayElement: HTMLDivElement;\n /** Whether Shift key is held (additive selection mode) */\n shiftHeld: boolean;\n /** Elements currently previewed as \"will be selected\" */\n previewedElements: Set<UUID>;\n}\n\n/**\n * State during bulk move operation (T023)\n */\nexport interface BulkDragState {\n /** Starting cursor position in world coordinates */\n dragStartWorld: THREE.Vector3;\n /** Snapshot of initial positions for all selected elements */\n initialPositions: Map<UUID, THREE.Vector3>;\n /** Wire IDs that need geometry updates during drag */\n affectedWireIds: Set<UUID>;\n /** Initial intermediate positions for selected wires (wireId -> array of positions) */\n initialWireIntermediatePositions: Map<UUID, THREE.Vector3[]>;\n}\n\n/** Minimum selection rectangle size in pixels to distinguish from click */\nconst MIN_SELECTION_RECT_SIZE = 5;\n\n// =============================================================================\n// Clipboard Interfaces (T038)\n// =============================================================================\n\n/**\n * Complete clipboard data structure for copy/paste\n * TODO : copy and paste edited enodes sourceType and components config\n */\nexport interface ClipboardData {\n /** Center of selection bounding box in grid coordinates */\n anchor: { x: number; y: number };\n /** Copied component definitions */\n components: ClipboardComponent[];\n /** Copied branching point definitions */\n branchingPoints: ClipboardBranchingPoint[];\n /** Copied wire definitions (only wires with both endpoints in selection) */\n wires: ClipboardWire[];\n}\n\n/**\n * Component data within clipboard\n */\nexport interface ClipboardComponent {\n /** Component type identifier */\n type: string;\n /** Position relative to clipboard anchor */\n relativePosition: { x: number; y: number };\n /** Rotation angle in degrees */\n rotation: number;\n /** Original element ID for wire remapping during paste */\n originalId: UUID;\n /** Original configuration data for the component */\n config: Map<string, string>;\n /** Original pins sourceTypes */\n pinSources: Array<ENodeSourceType | undefined | null>;\n}\n\n/**\n * Branching point data within clipboard\n */\nexport interface ClipboardBranchingPoint {\n /** Position relative to clipboard anchor */\n relativePosition: { x: number; y: number };\n /** Original element ID for wire remapping during paste */\n originalId: UUID;\n /** Source type of the branching point */\n source?: ENodeSourceType | undefined;\n}\n\n/**\n * Wire data within clipboard\n */\nexport interface ClipboardWire {\n /** Original ID of first endpoint (component pin or branching point) */\n node1OriginalId: UUID;\n /** Original ID of second endpoint */\n node2OriginalId: UUID;\n /** Intermediate positions relative to clipboard anchor */\n relativeIntermediatePositions: Array<{ x: number; y: number }>;\n}\n\n/**\n * MultiSelectTool implementation\n *\n * Provides functionality for:\n * - Rectangle selection of multiple elements\n * - Bulk move operations\n * - Bulk delete operations\n * - Copy/paste and cut/paste operations\n */\nexport class MultiSelectTool implements IEditingTool {\n readonly type = 'multiSelect' as const;\n\n private mode: MultiSelectToolMode = 'idle';\n private readonly controller: CircuitController;\n\n // Selection rectangle state\n private selectionRectState: SelectionRectState | null = null;\n\n // Bulk drag state (Phase 4)\n private bulkDragState: BulkDragState | null = null;\n\n // Clipboard state (Phase 6)\n private clipboardData: ClipboardData | null = null;\n // Maps pin IDs to their parent component IDs for wire reconstruction during paste\n private clipboardPinToComponent: Map<UUID, UUID> = new Map();\n // Maps pin IDs to their index within their parent component\n private clipboardPinIndices: Map<UUID, number> = new Map();\n\n // Bound event handlers for stable references\n private handlePointerDown: (event: PointerEvent) => void;\n private handlePointerMove: (event: PointerEvent) => void;\n private handlePointerUp: (event: PointerEvent) => void;\n private handleKeyDown: (event: KeyboardEvent) => void;\n private handleGridPositionMove: (position: THREE.Vector3) => void;\n\n constructor(controller: CircuitController) {\n this.controller = controller;\n\n // Bind event handlers\n this.handlePointerDown = this._handlePointerDown.bind(this);\n this.handlePointerMove = this._handlePointerMove.bind(this);\n this.handlePointerUp = this._handlePointerUp.bind(this);\n this.handleKeyDown = this._handleKeyDown.bind(this);\n this.handleGridPositionMove = this._handleGridPositionMove.bind(this);\n }\n\n /**\n * Get the current operating mode\n */\n getMode(): MultiSelectToolMode {\n return this.mode;\n }\n\n /**\n * Called when tool becomes active\n */\n onActivate(): void {\n this.mode = 'idle';\n this.selectionRectState = null;\n this.bulkDragState = null;\n\n // Register event listeners\n const container = this.controller.getContainer();\n container.addEventListener('pointerdown', this.handlePointerDown);\n container.addEventListener('pointermove', this.handlePointerMove);\n container.addEventListener('pointerup', this.handlePointerUp);\n window.addEventListener('keydown', this.handleKeyDown);\n }\n\n /**\n * Called when tool is deactivated\n */\n onDeactivate(): void {\n // Cancel any ongoing operation\n this.cancelOperation();\n\n // Unregister event listeners\n const container = this.controller.getContainer();\n container.removeEventListener('pointerdown', this.handlePointerDown);\n container.removeEventListener('pointermove', this.handlePointerMove);\n container.removeEventListener('pointerup', this.handlePointerUp);\n window.removeEventListener('keydown', this.handleKeyDown);\n this.controller.off('gridPositionMove', this.handleGridPositionMove);\n\n this.mode = 'idle';\n this.selectionRectState = null;\n this.bulkDragState = null;\n }\n\n /**\n * Cancel any in-progress operation\n */\n cancelOperation(): void {\n if (this.mode === 'selecting') {\n this._cancelSelectionRect();\n } else if (this.mode === 'dragging') {\n this._cancelBulkDrag();\n }\n }\n\n /**\n * Get the current cursor type for this tool (T031)\n */\n getCursorType(): CursorType {\n const hoveredElement = this.controller.getHoveredElement();\n const selectionManager = this.controller.getSelectionManager();\n\n switch (this.mode) {\n case 'selecting':\n return 'crosshair';\n case 'dragging':\n return 'grabbing';\n case 'idle':\n default:\n // T031: Check if hovering over a selected element (for drag cursor)\n if (hoveredElement) {\n const isSelected = selectionManager.isSelected(hoveredElement.type, hoveredElement.id);\n if (isSelected) {\n return 'grab';\n }\n // Hovering over an element that could be selected\n return 'pointer';\n }\n return 'default';\n }\n }\n\n /**\n * Get preview objects to render in the scene\n */\n getPreviewObjects(): THREE.Object3D[] {\n // Selection rectangle is rendered via CSS overlay, not THREE.js\n return [];\n }\n\n // ==========================================================================\n // Event Handlers\n // ==========================================================================\n\n /**\n * Handle pointer down event (T011, T019, T020, T021, T024)\n * - Empty space: start rectangle selection\n * - Element click: select that element (clear others unless Shift held)\n * - Selected element: prepare for bulk drag (Phase 4)\n */\n private _handlePointerDown(event: PointerEvent): void {\n if (event.button !== 0) return; // Only left click\n\n const hoveredElement = this.controller.getHoveredElement();\n const selectionManager = this.controller.getSelectionManager();\n const shiftHeld = event.shiftKey;\n\n if (this.mode === 'idle') {\n // Case 1: Clicking on an element\n if (hoveredElement) {\n const isSelected = selectionManager.isSelected(hoveredElement.type, hoveredElement.id);\n\n // T020: Shift-click adds to selection\n if (shiftHeld) {\n if (hoveredElement.type === 'wire') return; // Wires cannot be individually added/removed from selection\n if (!isSelected) {\n selectionManager.addToSelection(hoveredElement.type, hoveredElement.id);\n // TODO: also add wires connected to this element (need some refactoring on SelectionManager)\n } else {\n // If already selected toggle => remove from the selection with deselecting cascade\n selectionManager.removeFromSelection(hoveredElement.type, hoveredElement.id);\n if (hoveredElement.type === 'component') {\n const circuitComponent = this.controller\n .getCircuit()!\n .getComponent(hoveredElement.id);\n if (circuitComponent) {\n // Also remove its pins and connected wires from selection\n for (const pinId of circuitComponent.pins) {\n selectionManager.removeFromSelection('enode', pinId);\n const enode = this.controller.getCircuit()!.getENode(pinId);\n if (enode) {\n for (const wireId of enode.wires) {\n selectionManager.removeFromSelection('wire', wireId);\n }\n }\n }\n }\n }\n // enode without componentId means branching point\n else if (\n hoveredElement.type === 'enode' &&\n !hoveredElement.object3D.userData.componentId\n ) {\n const enode = this.controller.getCircuit()!.getENode(hoveredElement.id);\n if (enode) {\n for (const wireId of enode.wires) {\n selectionManager.removeFromSelection('wire', wireId);\n }\n }\n }\n }\n return;\n }\n\n // T019: Single click selects element (clears previous)\n if (\n !isSelected &&\n !(hoveredElement.type === 'enode' && !!hoveredElement.object3D.userData.componentId)\n ) {\n selectionManager.selectOne(hoveredElement.type, hoveredElement.id);\n return;\n }\n\n // T024: Clicking on already selected element - start bulk drag\n const worldPosition = this.controller.cursorGroundPlanePosition();\n this._startBulkDrag(worldPosition);\n return;\n }\n\n // Case 2: T021 - Click on empty space clears selection (if no drag started)\n // Case 3: T011 - Start rectangle selection on empty space\n const containerRect = this.controller.getContainer().getBoundingClientRect();\n const screenX = event.clientX - containerRect.left;\n const screenY = event.clientY - containerRect.top;\n\n this._startSelectionRect(screenX, screenY, shiftHeld);\n }\n }\n\n /**\n * Handle pointer move event (T013)\n * Updates rectangle dimensions during selection\n */\n private _handlePointerMove(event: PointerEvent): void {\n if (this.mode !== 'selecting' || !this.selectionRectState) return;\n\n const containerRect = this.controller.getContainer().getBoundingClientRect();\n const screenX = event.clientX - containerRect.left;\n const screenY = event.clientY - containerRect.top;\n\n // Update current screen position\n this.selectionRectState.currentScreen = { x: screenX, y: screenY };\n\n // Update CSS overlay position and size (T013)\n this._updateSelectionRectOverlay();\n\n // Update preview highlighting (T015)\n this._updatePreviewHighlighting();\n }\n\n /**\n * Handle pointer up event (T016, T021, T029)\n * Commits selection or bulk drag, or clears if it was just a click\n */\n private _handlePointerUp(event: PointerEvent): void {\n if (event.button !== 0) return; // Only left click\n\n if (this.mode === 'selecting' && this.selectionRectState) {\n const { startScreen, currentScreen, shiftHeld } = this.selectionRectState;\n\n // Calculate rectangle size\n const width = Math.abs(currentScreen.x - startScreen.x);\n const height = Math.abs(currentScreen.y - startScreen.y);\n\n // If rectangle is too small, treat as click (T021 - clear selection)\n if (width < MIN_SELECTION_RECT_SIZE && height < MIN_SELECTION_RECT_SIZE) {\n // T021: Click on empty space clears selection\n if (!shiftHeld) {\n this.controller.getSelectionManager().deselect();\n }\n this._cancelSelectionRect();\n return;\n }\n\n // T016: Commit selection\n this._commitSelectionRect();\n } else if (this.mode === 'dragging' && this.bulkDragState) {\n // T029: Commit bulk drag\n this._commitBulkDrag();\n }\n }\n\n /**\n * Handle grid position move event (T027)\n * Updates element positions during bulk drag\n */\n private _handleGridPositionMove(position: THREE.Vector3): void {\n if (this.mode === 'dragging' && this.bulkDragState) {\n this._updateBulkDrag(position);\n }\n }\n\n /**\n * Handle keyboard events (T017, T030, T034, T043, T048, T053)\n * - Escape: cancel current operation\n * - Delete/Backspace: delete selection\n * - Ctrl+C/Cmd+C: copy selection\n * - Ctrl+V/Cmd+V: paste clipboard\n * - Ctrl+X/Cmd+X: cut selection\n */\n private _handleKeyDown(event: KeyboardEvent): void {\n // T017, T030: Escape cancels rectangle selection or bulk drag\n if (event.key === 'Escape') {\n if (this.mode === 'selecting') {\n this._cancelSelectionRect();\n return;\n } else if (this.mode === 'dragging') {\n this._cancelBulkDrag();\n return;\n }\n }\n\n // T034: Delete/Backspace triggers bulk delete\n if (event.key === 'Delete' || event.key === 'Backspace') {\n // Only delete if we have a selection and we're idle (not during drag)\n if (this.mode === 'idle') {\n this.deleteSelection();\n }\n return;\n }\n\n // Detect Ctrl (Windows/Linux) or Cmd (Mac)\n const ctrlOrCmd = event.ctrlKey || event.metaKey;\n\n if (!ctrlOrCmd) return;\n\n // T043: Ctrl+C / Cmd+C - Copy selection\n if (event.key === 'c' || event.key === 'C') {\n if (this.mode === 'idle') {\n this.copySelection();\n }\n return;\n }\n\n // T048: Ctrl+V / Cmd+V - Paste clipboard\n if (event.key === 'v' || event.key === 'V') {\n if (this.mode === 'idle') {\n this.pasteAtCursor();\n }\n return;\n }\n\n // T053: Ctrl+X / Cmd+X - Cut selection\n if (event.key === 'x' || event.key === 'X') {\n if (this.mode === 'idle') {\n this.cutSelection();\n }\n return;\n }\n }\n\n // ==========================================================================\n // Selection Rectangle Operations (T012, T014, T015, T016, T018, T022)\n // ==========================================================================\n\n /**\n * Start rectangle selection (T012)\n */\n private _startSelectionRect(screenX: number, screenY: number, shiftHeld: boolean): void {\n // Create CSS overlay element\n const overlayElement = document.createElement('div');\n overlayElement.style.cssText = `\n position: absolute;\n border: 2px dashed #4a90d9;\n background: rgba(74, 144, 217, 0.1);\n pointer-events: none;\n z-index: 1000;\n `;\n this.controller.getContainer().appendChild(overlayElement);\n\n // Initialize state\n this.selectionRectState = {\n startScreen: { x: screenX, y: screenY },\n currentScreen: { x: screenX, y: screenY },\n overlayElement,\n shiftHeld,\n previewedElements: new Set(),\n };\n\n this.mode = 'selecting';\n\n // Lock camera controls\n const controls = this.controller.getControls();\n if (controls) {\n controls.enablePan = false;\n }\n\n // T022: Emit event\n this.controller.emit('toolOperationStarted', {\n toolType: this.type,\n mode: 'selecting',\n operationData: { startScreen: { x: screenX, y: screenY } },\n });\n }\n\n /**\n * Update CSS overlay dimensions and position (T013)\n */\n private _updateSelectionRectOverlay(): void {\n if (!this.selectionRectState) return;\n\n const { startScreen, currentScreen, overlayElement } = this.selectionRectState;\n\n const left = Math.min(startScreen.x, currentScreen.x);\n const top = Math.min(startScreen.y, currentScreen.y);\n const width = Math.abs(currentScreen.x - startScreen.x);\n const height = Math.abs(currentScreen.y - startScreen.y);\n\n overlayElement.style.left = `${left}px`;\n overlayElement.style.top = `${top}px`;\n overlayElement.style.width = `${width}px`;\n overlayElement.style.height = `${height}px`;\n }\n\n /**\n * Update preview highlighting for elements inside rectangle (T015)\n */\n private _updatePreviewHighlighting(): void {\n if (!this.selectionRectState) return;\n\n const elementsInRect = this._getElementsInSelectionRect();\n const newPreviewSet = new Set<UUID>();\n\n // Collect all element IDs\n for (const id of elementsInRect.components) {\n newPreviewSet.add(id);\n }\n for (const id of elementsInRect.enodes) {\n newPreviewSet.add(id);\n }\n for (const id of elementsInRect.wires) {\n newPreviewSet.add(id);\n }\n\n // Update preview state\n this.selectionRectState.previewedElements = newPreviewSet;\n\n // TODO: Visual preview highlighting could be implemented here\n // by applying temporary visual state to elements\n }\n\n /**\n * Get elements inside the current selection rectangle (T014)\n * Components/BPs: selected if center is inside rectangle\n * Wires: selected only if BOTH endpoints are selected\n */\n private _getElementsInSelectionRect(): {\n components: UUID[];\n enodes: UUID[];\n wires: UUID[];\n } {\n const result = {\n components: [] as UUID[],\n enodes: [] as UUID[],\n wires: [] as UUID[],\n };\n\n if (!this.selectionRectState) return result;\n\n const circuit = this.controller.getCircuit();\n if (!circuit) return result;\n\n const camera = this.controller.getCamera();\n const container = this.controller.getContainer();\n const width = container.clientWidth;\n const height = container.clientHeight;\n\n // Calculate screen rect bounds\n const { startScreen, currentScreen } = this.selectionRectState;\n const screenRect = {\n minX: Math.min(startScreen.x, currentScreen.x),\n minY: Math.min(startScreen.y, currentScreen.y),\n maxX: Math.max(startScreen.x, currentScreen.x),\n maxY: Math.max(startScreen.y, currentScreen.y),\n };\n\n // Set of selected enode IDs\n const selectedEnodeIds = new Set<UUID>();\n // Map of wire and number of their enodes selected\n const wireEnodeSelectionCount = new Map<UUID, number>();\n\n // Check components (T014)\n const componentObject3Ds = this.controller.componentObject3Ds;\n for (const [componentId, object3D] of componentObject3Ds) {\n const worldPos = new THREE.Vector3();\n object3D.getWorldPosition(worldPos);\n\n if (isPointInScreenRect(worldPos, camera, width, height, screenRect)) {\n result.components.push(componentId);\n\n // Mark component pins as selected for wire check\n const component = circuit.getComponent(componentId);\n if (component) {\n for (const pinId of component.pins) {\n selectedEnodeIds.add(pinId);\n const enode = circuit.getENode(pinId);\n if (!enode) continue;\n for (const wireId of enode.wires) {\n const currentCount = wireEnodeSelectionCount.get(wireId) || 0;\n wireEnodeSelectionCount.set(wireId, currentCount + 1);\n }\n }\n }\n }\n }\n\n // Check enodes (branching points only - pins are covered by components)\n const enodeObject3Ds = this.controller.enodeObject3Ds;\n for (const [enodeId, object3D] of enodeObject3Ds) {\n // Only select standalone branching points\n if (object3D.userData.componentId) continue; // Skip pins\n\n // Skip if already marked (pin of selected component)\n if (selectedEnodeIds.has(enodeId)) continue;\n\n const worldPos = new THREE.Vector3();\n object3D.getWorldPosition(worldPos);\n\n if (isPointInScreenRect(worldPos, camera, width, height, screenRect)) {\n result.enodes.push(enodeId);\n selectedEnodeIds.add(enodeId);\n const enode = circuit.getENode(enodeId);\n if (!enode) continue;\n for (const wireId of enode.wires) {\n const currentCount = wireEnodeSelectionCount.get(wireId) || 0;\n wireEnodeSelectionCount.set(wireId, currentCount + 1);\n }\n }\n }\n\n for (const [wireId, count] of wireEnodeSelectionCount) {\n // If both endpoints are selected, include the wire (T014)\n if (count >= 2) {\n result.wires.push(wireId);\n }\n }\n\n return result;\n }\n\n /**\n * Commit the rectangle selection (T016, T018, T022)\n */\n private _commitSelectionRect(): void {\n if (!this.selectionRectState) return;\n\n const elementsInRect = this._getElementsInSelectionRect();\n const selectionManager = this.controller.getSelectionManager();\n\n // Build selection maps\n const components = new Map<UUID, string | null>();\n const enodes = new Map<UUID, string | null>();\n const wires = new Map<UUID, string | null>();\n\n for (const id of elementsInRect.components) {\n components.set(id, null);\n }\n for (const id of elementsInRect.enodes) {\n enodes.set(id, null);\n }\n for (const id of elementsInRect.wires) {\n wires.set(id, null);\n }\n\n // T018: Additive selection mode\n if (this.selectionRectState.shiftHeld) {\n // Add new elements to existing selection\n const existing = selectionManager.getSelectedIds();\n for (const id of existing.components) {\n components.set(id, null);\n }\n for (const id of existing.enodes) {\n enodes.set(id, null);\n }\n for (const id of existing.wires) {\n wires.set(id, null);\n }\n }\n\n // Apply selection\n selectionManager.selectMultiple(components, enodes, wires);\n\n // T022: Emit completion event\n const totalCount = components.size + enodes.size + wires.size;\n this.controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'selecting',\n operationData: {\n selectedCount: totalCount,\n additive: this.selectionRectState.shiftHeld,\n },\n changedData: {},\n });\n\n // Cleanup\n this._cleanupSelectionRect();\n this.mode = 'idle';\n\n // Unlock camera controls\n const controls = this.controller.getControls();\n if (controls) {\n controls.enablePan = true;\n }\n }\n\n /**\n * Cancel rectangle selection (T017)\n */\n private _cancelSelectionRect(): void {\n if (!this.selectionRectState) return;\n\n // Emit cancellation event\n this.controller.emit('toolOperationCancelled', {\n toolType: this.type,\n mode: 'selecting',\n });\n\n // Cleanup\n this._cleanupSelectionRect();\n this.mode = 'idle';\n\n // Unlock camera controls\n const controls = this.controller.getControls();\n if (controls) {\n controls.enablePan = true;\n }\n }\n\n /**\n * Clean up selection rectangle overlay\n */\n private _cleanupSelectionRect(): void {\n if (this.selectionRectState?.overlayElement) {\n this.selectionRectState.overlayElement.remove();\n }\n this.selectionRectState = null;\n }\n\n // ==========================================================================\n // Bulk Drag Operations (T024-T032) - Phase 4\n // ==========================================================================\n\n /**\n * Start bulk drag operation (T024, T025, T026, T032)\n */\n private _startBulkDrag(worldPosition: THREE.Vector3): void {\n const circuit = this.controller.getCircuit();\n if (!circuit) return;\n\n const selectionManager = this.controller.getSelectionManager();\n const selectedIds = selectionManager.getSelectedIds();\n\n // T025: Capture initial positions for all selected elements\n const initialPositions = new Map<UUID, THREE.Vector3>();\n\n // Capture component positions\n for (const componentId of selectedIds.components) {\n const object3D = this.controller.componentObject3Ds.get(componentId);\n if (object3D) {\n initialPositions.set(componentId, object3D.position.clone());\n }\n }\n\n // Capture branching point positions\n for (const enodeId of selectedIds.enodes) {\n const object3D = this.controller.enodeObject3Ds.get(enodeId);\n if (object3D && !object3D.userData.componentId) {\n // Only branching points\n initialPositions.set(enodeId, object3D.position.clone());\n }\n }\n\n // T026: Collect affected wires (selected wires + boundary wires)\n const affectedWireIds = new Set<UUID>();\n\n // Add selected wires\n for (const wireId of selectedIds.wires) {\n affectedWireIds.add(wireId);\n }\n\n // Add boundary wires (wires connected to selected components/enodes but not fully selected)\n for (const componentId of selectedIds.components) {\n const component = circuit.getComponent(componentId);\n if (component) {\n for (const pinId of component.pins) {\n const enode = circuit.getENode(pinId);\n if (enode) {\n for (const wireId of enode.wires) {\n affectedWireIds.add(wireId);\n }\n }\n }\n }\n }\n\n for (const enodeId of selectedIds.enodes) {\n const enode = circuit.getENode(enodeId);\n if (enode) {\n for (const wireId of enode.wires) {\n affectedWireIds.add(wireId);\n }\n }\n }\n\n // Capture initial intermediate positions for selected wires\n const initialWireIntermediatePositions = new Map<UUID, THREE.Vector3[]>();\n for (const wireId of selectedIds.wires) {\n const wire = circuit.getWire(wireId);\n if (wire && wire.intermediatePositions.length > 0) {\n // Clone all intermediate positions\n const positions = wire.intermediatePositions.map((pos) => gridToWorldPosition(pos));\n initialWireIntermediatePositions.set(wireId, positions);\n }\n }\n\n // Initialize drag state\n this.bulkDragState = {\n dragStartWorld: worldPosition.clone(),\n initialPositions,\n affectedWireIds,\n initialWireIntermediatePositions,\n };\n\n this.mode = 'dragging';\n\n // Lock camera controls\n const controls = this.controller.getControls();\n if (controls) {\n controls.enablePan = false;\n }\n\n // Register for grid position move events\n this.controller.on('gridPositionMove', this.handleGridPositionMove);\n\n // T032: Emit event\n this.controller.emit('toolOperationStarted', {\n toolType: this.type,\n mode: 'dragging',\n operationData: { elementCount: initialPositions.size },\n });\n }\n\n /**\n * Update bulk drag - apply delta to all selected elements (T027, T028)\n */\n private _updateBulkDrag(worldPosition: THREE.Vector3): void {\n if (!this.bulkDragState) return;\n\n const { dragStartWorld, initialPositions, affectedWireIds, initialWireIntermediatePositions } =\n this.bulkDragState;\n\n // we retrieve unbound world position to avoid snapping during drag since Multi Select tool allows to expand grid\n worldPosition = this.controller.cursorGroundPlanePosition(false);\n\n // Calculate delta\n const delta = new THREE.Vector3().subVectors(worldPosition, dragStartWorld);\n\n // T027: Apply delta to all selected elements\n for (const [elementId, initialPos] of initialPositions) {\n const newPosition = new THREE.Vector3().addVectors(initialPos, delta);\n const snappedPosition = nearestWorldSnapPosition(newPosition);\n\n // Update component visual\n const componentObject3D = this.controller.componentObject3Ds.get(elementId);\n if (componentObject3D) {\n componentObject3D.position.copy(snappedPosition);\n\n // Update component in circuit model\n this.controller.circuitWriter.saveEditComponent(elementId, componentObject3D);\n continue;\n }\n\n // Update branching point visual\n const enodeObject3D = this.controller.enodeObject3Ds.get(elementId);\n if (enodeObject3D) {\n enodeObject3D.position.copy(snappedPosition);\n\n // Update branching point in circuit model\n this.controller.circuitWriter.saveEditBranchingPoint(enodeObject3D);\n }\n }\n\n // Apply delta to intermediate positions of selected wires\n\n for (const [wireId, initialIntermediatePositions] of initialWireIntermediatePositions) {\n // Apply delta to each intermediate position\n const updatedPositions = initialIntermediatePositions.map((pos) => {\n const newPos = new THREE.Vector3().addVectors(pos, delta);\n return worldToGridPosition(newPos);\n });\n\n // Update wire intermediate positions in circuit model\n this.controller.circuitWriter.saveEditWirePositions(wireId, updatedPositions, false);\n }\n\n // T028: Update wire geometry for all affected wires\n const wireVisualManager = this.controller.wireVisualManager;\n for (const wireId of affectedWireIds) {\n wireVisualManager.updateWireById(wireId);\n }\n }\n\n /**\n * Commit bulk drag operation (T029, T032)\n */\n private _commitBulkDrag(): void {\n if (!this.bulkDragState) return;\n\n const circuit = this.controller.getCircuit();\n if (!circuit) return;\n\n const { dragStartWorld, initialPositions } = this.bulkDragState;\n const currentPosition = this.controller.cursorGroundPlanePosition(false);\n\n // Calculate final delta\n const delta = new THREE.Vector3().subVectors(currentPosition, dragStartWorld);\n const gridDelta = worldToGridPosition(delta);\n\n // T032: Emit completion event\n this.controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'dragging',\n operationData: {\n elementCount: initialPositions.size,\n delta: { x: gridDelta.x, y: gridDelta.y },\n },\n changedData: {},\n });\n\n // launch autoAdjust of the grid after bulk move\n this.controller.autoAdjustCircuitGridSize();\n\n // Cleanup\n this.mode = 'idle';\n this.bulkDragState = null;\n\n // Unregister grid position move listener\n this.controller.off('gridPositionMove', this.handleGridPositionMove);\n\n // Unlock camera controls\n const controls = this.controller.getControls();\n if (controls) {\n controls.enablePan = true;\n }\n }\n\n /**\n * Cancel bulk drag operation - revert all elements to initial positions (T030)\n */\n private _cancelBulkDrag(): void {\n if (!this.bulkDragState) return;\n\n const { initialPositions, affectedWireIds, initialWireIntermediatePositions } =\n this.bulkDragState;\n\n // Revert all elements to initial positions\n for (const [elementId, initialPos] of initialPositions) {\n const componentObject3D = this.controller.componentObject3Ds.get(elementId);\n if (componentObject3D) {\n componentObject3D.position.copy(initialPos);\n this.controller.circuitWriter.saveEditComponent(elementId, componentObject3D);\n continue;\n }\n\n const enodeObject3D = this.controller.enodeObject3Ds.get(elementId);\n if (enodeObject3D) {\n enodeObject3D.position.copy(initialPos);\n this.controller.circuitWriter.saveEditBranchingPoint(enodeObject3D);\n }\n }\n\n // Revert intermediate positions of selected wires\n for (const [wireId, initialIntermediatePositions] of initialWireIntermediatePositions) {\n const positions = initialIntermediatePositions.map((pos) => worldToGridPosition(pos));\n this.controller.circuitWriter.saveEditWirePositions(wireId, positions, false);\n }\n\n // Update all affected wires\n const wireVisualManager = this.controller.wireVisualManager;\n for (const wireId of affectedWireIds) {\n wireVisualManager.updateWireById(wireId);\n }\n\n // Emit cancellation event\n this.controller.emit('toolOperationCancelled', {\n toolType: this.type,\n mode: 'dragging',\n });\n\n // Cleanup\n this.mode = 'idle';\n this.bulkDragState = null;\n\n // Unregister grid position move listener\n this.controller.off('gridPositionMove', this.handleGridPositionMove);\n\n // Unlock camera controls\n const controls = this.controller.getControls();\n if (controls) {\n controls.enablePan = true;\n }\n }\n\n // ==========================================================================\n // Copy/Paste Operations (T039-T051) - Phase 6\n // ==========================================================================\n\n /**\n * Check if clipboard has content (T050)\n */\n hasClipboardContent(): boolean {\n return this.clipboardData !== null;\n }\n\n /**\n * Copy current selection to clipboard (T039, T040, T041, T042, T051)\n * @returns true if copy succeeded (non-empty selection)\n */\n copySelection(): boolean {\n const circuit = this.controller.getCircuit();\n if (!circuit) return false;\n\n const selectionManager = this.controller.getSelectionManager();\n const selectedIds = selectionManager.getSelectedIds();\n\n // Empty selection - no-op\n if (\n selectedIds.components.length === 0 &&\n selectedIds.enodes.length === 0 &&\n selectedIds.wires.length === 0\n ) {\n return false;\n }\n\n // T040: Calculate anchor (center of selection bounding box)\n const bounds = {\n minX: Infinity,\n maxX: -Infinity,\n minY: Infinity,\n maxY: -Infinity,\n };\n\n // Gather component positions\n for (const componentId of selectedIds.components) {\n const component = circuit.getComponent(componentId);\n if (component) {\n const pos = component.position;\n bounds.minX = Math.min(bounds.minX, pos.x);\n bounds.maxX = Math.max(bounds.maxX, pos.x);\n bounds.minY = Math.min(bounds.minY, pos.y);\n bounds.maxY = Math.max(bounds.maxY, pos.y);\n }\n }\n\n // Gather branching point positions\n for (const enodeId of selectedIds.enodes) {\n const enode = circuit.getENode(enodeId);\n if (enode && enode.position) {\n const pos = enode.position;\n bounds.minX = Math.min(bounds.minX, pos.x);\n bounds.maxX = Math.max(bounds.maxX, pos.x);\n bounds.minY = Math.min(bounds.minY, pos.y);\n bounds.maxY = Math.max(bounds.maxY, pos.y);\n }\n }\n\n const anchor = {\n x: (bounds.minX + bounds.maxX) / 2,\n y: (bounds.minY + bounds.maxY) / 2,\n };\n\n // T041: Serialize components with relative positions\n const clipboardComponents: ClipboardComponent[] = [];\n for (const componentId of selectedIds.components) {\n const component = circuit.getComponent(componentId);\n if (component) {\n const pos = component.position;\n const sources = component.pins.map((pinId) => {\n const enode = circuit.getENode(pinId);\n return enode ? enode.source : null;\n });\n clipboardComponents.push({\n type: component.type,\n relativePosition: {\n x: pos.x - anchor.x,\n y: pos.y - anchor.y,\n },\n rotation: component.rotation.angle,\n originalId: componentId,\n pinSources: sources,\n config: new Map(component.config), // Deep copy of config\n });\n }\n }\n\n // T041: Serialize branching points with relative positions\n const clipboardBranchingPoints: ClipboardBranchingPoint[] = [];\n for (const enodeId of selectedIds.enodes) {\n const enode = circuit.getENode(enodeId);\n if (enode && enode.position) {\n const pos = enode.position;\n clipboardBranchingPoints.push({\n relativePosition: {\n x: pos.x - anchor.x,\n y: pos.y - anchor.y,\n },\n originalId: enodeId,\n source: enode.source,\n });\n }\n }\n\n // T042: Serialize wires (only wires with both endpoints in selection)\n // Create set of all selected endpoint IDs (component pins + branching points)\n const selectedEndpointIds = new Set<UUID>();\n\n // Also build pin-to-component mapping and pin indices for paste operation\n this.clipboardPinToComponent.clear();\n this.clipboardPinIndices.clear();\n\n // Add component pins\n for (const componentId of selectedIds.components) {\n const component = circuit.getComponent(componentId);\n if (component) {\n for (let i = 0; i < component.pins.length; i++) {\n const pinId = component.pins[i];\n if (pinId) {\n selectedEndpointIds.add(pinId);\n this.clipboardPinToComponent.set(pinId, componentId);\n this.clipboardPinIndices.set(pinId, i);\n }\n }\n }\n }\n\n // Add branching points\n for (const enodeId of selectedIds.enodes) {\n selectedEndpointIds.add(enodeId);\n }\n\n const clipboardWires: ClipboardWire[] = [];\n for (const wireId of selectedIds.wires) {\n const wire = circuit.getWire(wireId);\n if (!wire) continue;\n\n // Only include wire if both endpoints are in selection\n if (selectedEndpointIds.has(wire.node1) && selectedEndpointIds.has(wire.node2)) {\n // Calculate relative intermediate positions\n const relativeIntermediatePositions = wire.intermediatePositions.map((pos) => ({\n x: pos.x - anchor.x,\n y: pos.y - anchor.y,\n }));\n\n clipboardWires.push({\n node1OriginalId: wire.node1,\n node2OriginalId: wire.node2,\n relativeIntermediatePositions,\n });\n }\n }\n\n // Store clipboard data\n this.clipboardData = {\n anchor,\n components: clipboardComponents,\n branchingPoints: clipboardBranchingPoints,\n wires: clipboardWires,\n };\n\n // T051: Emit copy completed event\n this.controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'copy',\n operationData: {\n componentCount: clipboardComponents.length,\n branchingPointCount: clipboardBranchingPoints.length,\n wireCount: clipboardWires.length,\n },\n changedData: {},\n });\n\n return true;\n }\n\n /**\n * Paste clipboard content at cursor position (T044, T045, T046, T047, T049, T051)\n * @returns true if paste succeeded (non-empty clipboard)\n */\n pasteAtCursor(): boolean {\n if (!this.clipboardData) return false;\n\n const circuit = this.controller.getCircuit();\n if (!circuit) return false;\n\n const cursorPosition = this.controller.cursorGroundPlanePosition(false);\n const gridCursor = worldToGridPosition(cursorPosition);\n\n // Map from original IDs to newly created element IDs for wire remapping (T047)\n const idRemap = new Map<UUID, UUID>();\n\n // T045: Create components from clipboard\n const createdComponentIds: UUID[] = [];\n for (const clipComponent of this.clipboardData.components) {\n const newGridPos = new Position(\n Math.round(gridCursor.x + clipComponent.relativePosition.x),\n Math.round(gridCursor.y + clipComponent.relativePosition.y)\n );\n\n const worldPos = gridToWorldPosition(newGridPos);\n const rotation = gridToWorldRotation(new Rotation(clipComponent.rotation));\n\n try {\n const newComponent = this.controller.addComponent(\n clipComponent.type as ComponentType,\n worldPos,\n rotation,\n clipComponent.config,\n clipComponent.pinSources\n );\n\n createdComponentIds.push(newComponent.id);\n\n // Map original component ID → new component ID\n idRemap.set(clipComponent.originalId, newComponent.id);\n\n // Map original pin IDs → new pin IDs using stored pin indices\n // This works even after cut (when original component no longer exists)\n for (const [originalPinId, originalComponentId] of this.clipboardPinToComponent) {\n if (originalComponentId === clipComponent.originalId) {\n const pinIndex = this.clipboardPinIndices.get(originalPinId);\n if (pinIndex !== undefined && pinIndex < newComponent.pins.length) {\n const newPinId = newComponent.pins[pinIndex];\n if (newPinId) {\n idRemap.set(originalPinId, newPinId);\n }\n }\n }\n }\n } catch (error) {\n console.error('Failed to paste component:', error);\n }\n }\n\n // T046: Create branching points from clipboard\n const createdBranchingPointIds: UUID[] = [];\n for (const clipBP of this.clipboardData.branchingPoints) {\n const newGridPos = new Position(\n Math.round(gridCursor.x + clipBP.relativePosition.x),\n Math.round(gridCursor.y + clipBP.relativePosition.y)\n );\n\n const worldPos = gridToWorldPosition(newGridPos);\n\n try {\n const newEnode = this.controller.addBranchingPoint(worldPos, clipBP.source);\n createdBranchingPointIds.push(newEnode.id);\n\n // Map original BP ID → new BP ID\n idRemap.set(clipBP.originalId, newEnode.id);\n } catch (error) {\n console.error('Failed to paste branching point:', error);\n }\n }\n\n // T047: Create wires with ID remapping\n const createdWireIds: UUID[] = [];\n for (const clipWire of this.clipboardData.wires) {\n const newNode1 = idRemap.get(clipWire.node1OriginalId);\n const newNode2 = idRemap.get(clipWire.node2OriginalId);\n\n // Only create wire if both endpoints were successfully created\n if (newNode1 && newNode2) {\n try {\n const newWire = this.controller.addWire(newNode1, newNode2);\n createdWireIds.push(newWire.id);\n\n // Update intermediate positions if any\n if (clipWire.relativeIntermediatePositions.length > 0) {\n const absolutePositions = clipWire.relativeIntermediatePositions.map((relPos) => ({\n x: Math.round(gridCursor.x + relPos.x),\n y: Math.round(gridCursor.y + relPos.y),\n }));\n\n this.controller.circuitWriter.saveEditWirePositions(\n newWire.id,\n absolutePositions,\n true\n );\n this.controller.wireVisualManager.updateWireById(newWire.id);\n }\n } catch (error) {\n console.error('Failed to paste wire:', error);\n }\n }\n }\n\n // T049: Select pasted elements\n const selectionManager = this.controller.getSelectionManager();\n const componentsMap = new Map<UUID, string | null>();\n const enodesMap = new Map<UUID, string | null>();\n const wiresMap = new Map<UUID, string | null>();\n\n for (const id of createdComponentIds) {\n componentsMap.set(id, null);\n }\n for (const id of createdBranchingPointIds) {\n enodesMap.set(id, null);\n }\n for (const id of createdWireIds) {\n wiresMap.set(id, null);\n }\n\n selectionManager.selectMultiple(componentsMap, enodesMap, wiresMap);\n\n // T051: Emit paste completed event\n this.controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'paste',\n operationData: {\n componentCount: createdComponentIds.length,\n branchingPointCount: createdBranchingPointIds.length,\n wireCount: createdWireIds.length,\n position: { x: gridCursor.x, y: gridCursor.y },\n },\n changedData: {},\n });\n\n // launch autoAdjust of the grid after bulk paste\n this.controller.autoAdjustCircuitGridSize();\n\n return true;\n }\n\n // ==========================================================================\n // Cut/Paste Operations (T052-T053) - Phase 7\n // ==========================================================================\n\n /**\n * Cut current selection (copy + delete) (T052)\n * @returns true if cut succeeded\n */\n cutSelection(): boolean {\n // Copy first\n const copySuccess = this.copySelection();\n if (!copySuccess) return false;\n\n // Then delete\n this.deleteSelection();\n return true;\n }\n\n // ==========================================================================\n // Bulk Delete Operations (T033-T037) - Phase 5\n // ==========================================================================\n\n /**\n * Delete all selected elements (T033, T034, T035, T036, T037)\n *\n * Deletion order per research.md:\n * 1. Selected wires\n * 2. Selected components (cascades to connected wires)\n * 3. Selected branching points\n */\n deleteSelection(): boolean {\n const selectionManager = this.controller.getSelectionManager();\n const selectedIds = selectionManager.getSelectedIds();\n\n const totalCount =\n selectedIds.components.length + selectedIds.enodes.length + selectedIds.wires.length;\n\n // No selection to delete\n if (totalCount === 0) {\n return false;\n }\n\n // T033: Delete in order: wires → components → branching points\n\n // 1. Delete selected wires\n for (const wireId of selectedIds.wires) {\n this.controller.removeWire(wireId);\n }\n\n // 2. Delete selected components (T035: cascades to connected wires - orphaned cleanup)\n for (const componentId of selectedIds.components) {\n this.controller.removeComponent(componentId);\n }\n\n // 3. Delete selected branching points\n for (const enodeId of selectedIds.enodes) {\n this.controller.removeBranchingPoint(enodeId);\n }\n\n // T037: Emit bulk delete event\n this.controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'bulk_delete',\n operationData: {\n componentCount: selectedIds.components.length,\n branchingPointCount: selectedIds.enodes.length,\n wireCount: selectedIds.wires.length,\n },\n changedData: {},\n });\n\n // launch autoAdjust of the grid after bulk delete\n this.controller.autoAdjustCircuitGridSize();\n\n // T036: Clear selection after delete\n selectionManager.deselect();\n\n return true;\n }\n}\n","/**\n * Selection Manager\n * @module scene/shared/SelectionManager\n *\n * Manages component selection state in the circuit scene.\n * However controller handles applying or not visuals for selection, based on current toolState.\n * Follows a similar pattern as HoverManager for consistency.\n */\n\nimport type { UUID } from 'simple-circuit-engine/core';\nimport { ENodeType } from 'simple-circuit-engine/core';\nimport type { HoverableType, SelectionData, MultiSelectionData } from './types';\n\n/**\n * Callback invoked when selection changes\n *\n * @param newSelection - The new selection, or null if deselected\n * @param previousSelection - The previous selection, or null if none was selected\n */\nexport type SelectionCallback = (\n newSelection: SelectionData | null,\n previousSelection: SelectionData | null\n) => void;\n\n/**\n * Manages selected components, enodes or wires for the circuit scene.\n * Multi-selection is planned (notably with the use of a flexible SelectionData) but still to implement.\n *\n * Key current responsibilities:\n * - Track -currently single object- selection state\n * - Notify listeners of selection changes (observer pattern)\n *\n * @example\n * ```typescript\n * const selectionManager = new SelectionManager();\n *\n *\n * // Select a single object\n * selectionManager.selectOne('component', 'component-uuid-1234');\n * selectionManager.selectOne('enode', 'enode-uuid-1234');\n * selectionManager.selectOne('wire', 'wire-uuid-1234');\n *\n * // Deselect\n * selectionManager.deselect();\n * ```\n */\nexport class SelectionManager {\n /** Current selection */\n private selection: SelectionData | null = null;\n\n /** Timestamp when selection occurred (for double-click detection) */\n private selectedAt: number | null = null;\n\n /** Registered selection change callbacks */\n private callbacks: Set<SelectionCallback> = new Set();\n\n /**\n * Create a new SelectionManager\n */\n constructor() {}\n\n /**\n * Get the current selection\n *\n * @returns The SelectionData, or null if nothing is selected\n */\n getSelection(): SelectionData | null {\n return this.selection;\n }\n\n /**\n * Get the timestamp when selection occurred\n *\n * @returns Timestamp in milliseconds, or null if nothing is selected\n */\n getSelectedAt(): number | null {\n return this.selectedAt;\n }\n\n /**\n * Check if a specific object is selected\n *\n * @param type - The type of hoverable object\n * @param objectId - The object ID to check\n * @returns true if the object is currently selected\n */\n isSelected(type: HoverableType, objectId: UUID): boolean {\n if (!this.selection) {\n return false;\n }\n if (this.selection.kind === 'mono') {\n return this.selection.type === type && this.selection.id === objectId;\n }\n if (this.selection.kind === 'multi') {\n if (type === 'component') {\n return this.selection.components?.has(objectId) ?? false;\n }\n if (type === 'enode') {\n return this.selection.enodes?.has(objectId) ?? false;\n }\n if (type === 'wire') {\n return this.selection.wires?.has(objectId) ?? false;\n }\n }\n return false;\n }\n\n /**\n * Check if anything is selected\n *\n * @returns true if one object is currently selected or several objects are currently selected\n */\n hasSelection(): boolean {\n return this.selection !== null;\n }\n\n private _selectionsEqual(a: SelectionData | null, b: SelectionData | null): boolean {\n if (a === b) {\n return true;\n }\n if (a === null || b === null) {\n return false;\n }\n if (a.kind !== b.kind) {\n return false;\n }\n if (a.kind === 'mono' && b.kind === 'mono') {\n return a.id === b.id;\n }\n if (a.kind === 'multi' && b.kind === 'multi') {\n const aComponents = a.components ?? new Map<UUID, string | null>();\n const bComponents = b.components ?? new Map<UUID, string | null>();\n const aEnodes = a.enodes ?? new Map<UUID, string | null>();\n const bEnodes = b.enodes ?? new Map<UUID, string | null>();\n const aWires = a.wires ?? new Map<UUID, string | null>();\n const bWires = b.wires ?? new Map<UUID, string | null>();\n\n if (\n aComponents.size !== bComponents.size ||\n aEnodes.size !== bEnodes.size ||\n aWires.size !== bWires.size\n ) {\n return false;\n }\n\n for (const id of aComponents.keys()) {\n if (!bComponents.has(id)) {\n return false;\n }\n }\n for (const id of aEnodes.keys()) {\n if (!bEnodes.has(id)) {\n return false;\n }\n }\n for (const id of aWires.keys()) {\n if (!bWires.has(id)) {\n return false;\n }\n }\n }\n return true;\n }\n\n /**\n * Select one object\n *\n * If another object was previously selected or a multi selection existed, they will be deselected first.\n *\n * @param type - The type of hoverable object to select\n * @param objectId - The object ID to select\n * @param userData - Optional userData of the 3D object being selected\n */\n selectOne(type: HoverableType, objectId: UUID, userData?: object | undefined): void {\n const previousSelection = this.selection;\n const newSelection: SelectionData = { kind: 'mono', type: type, id: objectId, data: null };\n\n // No change if selections are equal\n if (this._selectionsEqual(newSelection, previousSelection)) {\n return;\n }\n\n if (type === 'enode' && !!userData) {\n // @ts-ignore\n newSelection.data = !userData['componentId'] ? ENodeType.BranchingPoint : ENodeType.Pin;\n }\n\n // Update state\n this.selection = newSelection;\n this.selectedAt = Date.now();\n\n // Notify callbacks\n this.notifyCallbacks(newSelection, previousSelection);\n }\n\n /**\n * Deselect the current selection\n */\n deselect(): void {\n const previousSelection = this.selection;\n // Nothing to deselect\n if (!previousSelection) {\n return;\n }\n // Clear state\n this.selection = null;\n this.selectedAt = null;\n\n // Notify callbacks\n this.notifyCallbacks(null, previousSelection);\n }\n\n /**\n * Select multiple elements at once, replacing any existing selection\n *\n * Creates a MultiSelectionData with the provided element maps.\n * Empty maps are allowed; passing all empty maps clears the selection.\n *\n * @param components - Map of component IDs to optional metadata\n * @param enodes - Map of enode IDs to optional metadata\n * @param wires - Map of wire IDs to optional metadata\n */\n selectMultiple(\n components?: Map<UUID, string | null>,\n enodes?: Map<UUID, string | null>,\n wires?: Map<UUID, string | null>\n ): void {\n const previousSelection = this.selection;\n\n // Check if all maps are empty - treat as deselect\n const totalCount = (components?.size ?? 0) + (enodes?.size ?? 0) + (wires?.size ?? 0);\n\n if (totalCount === 0) {\n this.deselect();\n return;\n }\n\n const newSelection: MultiSelectionData = {\n kind: 'multi',\n ...(components && components.size > 0 ? { components } : {}),\n ...(enodes && enodes.size > 0 ? { enodes } : {}),\n ...(wires && wires.size > 0 ? { wires } : {}),\n };\n\n // No change if selections are equal\n if (this._selectionsEqual(newSelection, previousSelection)) {\n return;\n }\n\n // Update state\n this.selection = newSelection;\n this.selectedAt = Date.now();\n\n // Notify callbacks\n this.notifyCallbacks(newSelection, previousSelection);\n }\n\n /**\n * Add a single element to the current selection\n *\n * If current selection is null, creates a mono selection.\n * If current selection is mono, converts to multi and adds element.\n * If current selection is multi, adds element to appropriate map.\n *\n * No-op if element is already selected.\n *\n * @param type - Type of element to add\n * @param objectId - UUID of element to add\n * @param userData - Optional metadata for the element\n */\n addToSelection(type: HoverableType, objectId: UUID, userData?: object): void {\n // If already selected, no-op\n if (this.isSelected(type, objectId)) {\n return;\n }\n\n const previousSelection = this.selection;\n\n // If no selection, create mono selection\n if (!previousSelection) {\n this.selectOne(type, objectId, userData);\n return;\n }\n\n // If mono selection, convert to multi\n if (previousSelection.kind === 'mono') {\n const components = new Map<UUID, string | null>();\n const enodes = new Map<UUID, string | null>();\n const wires = new Map<UUID, string | null>();\n\n // Add existing selection\n if (previousSelection.type === 'component') {\n components.set(previousSelection.id, previousSelection.data ?? null);\n } else if (previousSelection.type === 'enode') {\n enodes.set(previousSelection.id, previousSelection.data ?? null);\n } else if (previousSelection.type === 'wire') {\n wires.set(previousSelection.id, previousSelection.data ?? null);\n }\n\n // Add new element\n if (type === 'component') {\n components.set(objectId, null);\n } else if (type === 'enode') {\n enodes.set(objectId, null);\n } else if (type === 'wire') {\n wires.set(objectId, null);\n }\n\n this.selectMultiple(components, enodes, wires);\n return;\n }\n\n // If multi selection, add to appropriate map\n if (previousSelection.kind === 'multi') {\n const components = new Map(previousSelection.components ?? new Map());\n const enodes = new Map(previousSelection.enodes ?? new Map());\n const wires = new Map(previousSelection.wires ?? new Map());\n\n if (type === 'component') {\n components.set(objectId, null);\n } else if (type === 'enode') {\n enodes.set(objectId, null);\n } else if (type === 'wire') {\n wires.set(objectId, null);\n }\n\n this.selectMultiple(components, enodes, wires);\n }\n }\n\n /**\n * Remove a single element from the current selection\n *\n * If element is in a mono selection, clears the selection.\n * If element is in a multi selection, removes from appropriate map.\n * If multi selection becomes single element, converts to mono.\n *\n * No-op if element is not selected.\n *\n * @param type - Type of element to remove\n * @param objectId - UUID of element to remove\n */\n removeFromSelection(type: HoverableType, objectId: UUID): void {\n // If not selected, no-op\n if (!this.isSelected(type, objectId)) {\n return;\n }\n\n const previousSelection = this.selection;\n\n if (!previousSelection) {\n return;\n }\n\n // If mono selection, deselect\n if (previousSelection.kind === 'mono') {\n this.deselect();\n return;\n }\n\n // If multi selection, remove from appropriate map\n if (previousSelection.kind === 'multi') {\n const components = new Map(previousSelection.components ?? new Map());\n const enodes = new Map(previousSelection.enodes ?? new Map());\n const wires = new Map(previousSelection.wires ?? new Map());\n\n if (type === 'component') {\n components.delete(objectId);\n } else if (type === 'enode') {\n enodes.delete(objectId);\n } else if (type === 'wire') {\n wires.delete(objectId);\n }\n\n const totalCount = components.size + enodes.size + wires.size;\n\n // If only one element left, convert to mono\n if (totalCount === 1) {\n if (components.size === 1) {\n for (const [id, data] of components.entries()) {\n this.selectOne('component', id, data ? { data } : undefined);\n return;\n }\n } else if (enodes.size === 1) {\n for (const [id, data] of enodes.entries()) {\n this.selectOne('enode', id, data ? { data } : undefined);\n return;\n }\n } else if (wires.size === 1) {\n for (const [id, data] of wires.entries()) {\n this.selectOne('wire', id, data ? { data } : undefined);\n return;\n }\n }\n return;\n }\n\n // Otherwise, update multi selection\n this.selectMultiple(components, enodes, wires);\n }\n }\n\n /**\n * Get the total count of selected elements across all types\n *\n * @returns Number of selected elements (0 if no selection)\n */\n getSelectionCount(): number {\n if (!this.selection) {\n return 0;\n }\n\n if (this.selection.kind === 'mono') {\n return 1;\n }\n\n if (this.selection.kind === 'multi') {\n return (\n (this.selection.components?.size ?? 0) +\n (this.selection.enodes?.size ?? 0) +\n (this.selection.wires?.size ?? 0)\n );\n }\n\n return 0;\n }\n\n /**\n * Get all selected element IDs grouped by type\n *\n * Returns empty arrays if no selection.\n * For mono selection, returns single-element array in appropriate category.\n *\n * @returns Object with arrays of selected IDs by type\n */\n getSelectedIds(): {\n components: UUID[];\n enodes: UUID[];\n wires: UUID[];\n } {\n if (!this.selection) {\n return { components: [], enodes: [], wires: [] };\n }\n\n if (this.selection.kind === 'mono') {\n if (this.selection.type === 'component') {\n return { components: [this.selection.id], enodes: [], wires: [] };\n }\n if (this.selection.type === 'enode') {\n return { components: [], enodes: [this.selection.id], wires: [] };\n }\n if (this.selection.type === 'wire') {\n return { components: [], enodes: [], wires: [this.selection.id] };\n }\n }\n\n if (this.selection.kind === 'multi') {\n return {\n components: Array.from(this.selection.components?.keys() ?? []),\n enodes: Array.from(this.selection.enodes?.keys() ?? []),\n wires: Array.from(this.selection.wires?.keys() ?? []),\n };\n }\n\n return { components: [], enodes: [], wires: [] };\n }\n\n /**\n * Register a callback for selection changes\n *\n * @param callback - Function to call when selection changes\n * @returns Unsubscribe function\n */\n onSelectionChange(callback: SelectionCallback): () => void {\n this.callbacks.add(callback);\n\n return () => {\n this.callbacks.delete(callback);\n };\n }\n\n /**\n * Notify all registered callbacks of selection change\n *\n * @param newSelection - New selection\n * @param previousSelection - Previous selection\n */\n private notifyCallbacks(\n newSelection: SelectionData | null,\n previousSelection: SelectionData | null\n ): void {\n for (const callback of this.callbacks) {\n try {\n callback(newSelection, previousSelection);\n } catch (error) {\n console.error('Selection callback error:', error);\n }\n }\n }\n\n /**\n * Clean up resources\n */\n dispose(): void {\n this.selection = null;\n this.selectedAt = null;\n this.callbacks.clear();\n }\n}\n","/**\n * CircuitWriter that centralizes all write operations on core circuit objects\n * @module scene/static/CircuitWriter\n */\nimport { Euler, Object3D, Vector3 } from 'three';\nimport type { ENodeSourceType, UUID, ENode, Wire, Component } from 'simple-circuit-engine/core';\nimport { Position, ComponentType, CameraOptions, Position3D } from 'simple-circuit-engine/core';\n\nimport type { CircuitController } from './CircuitController';\nimport type { ControllerEventMap } from '../shared/types';\nimport { computeDivisionsForSize, worldToGridPosition, worldToGridRotation } from '../shared/utils/GeometryUtils';\n\n/**\n * Manages editing operations of 3D models from the circuit scene into the core circuit model.\n */\nexport class CircuitWriter {\n private _controller: CircuitController;\n\n constructor(controller: CircuitController) {\n this._controller = controller;\n }\n\n /**\n * add branching point to the core circuit model and emits the appropriate event.\n * @param position - the world position to add the branching point at\n * @param sourceType - optional source type for the branching point\n * @throws Error\n * @return The circuit enode\n */\n saveAddBranchingPoint(position: Vector3, sourceType?: ENodeSourceType | undefined) {\n const circuit = this._controller.getCircuit();\n try {\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n\n const modelPosition = worldToGridPosition(position);\n const circuitEnode = circuit.addBranchingPoint(modelPosition, sourceType);\n\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'enode',\n action: 'add',\n id: circuitEnode.id,\n error: null,\n data: {\n position: modelPosition,\n sourceType: sourceType,\n },\n };\n this._controller.emit('circuitElementAction', event);\n return circuitEnode;\n } catch (error) {\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'enode',\n action: 'add',\n id: undefined,\n error: error as Error,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n throw new Error((error as Error).message);\n }\n }\n\n /**\n * edit branching point to the core circuit model and emits the appropriate event.\n * @param branchingPoint - the branching point Object3D\n * @param emit - should the event be emitted if commit OK (error event will always be)\n * @throws Error\n * @return The circuit enode\n */\n saveEditBranchingPoint(branchingPoint: Object3D, emit: boolean = false) {\n const circuit = this._controller.getCircuit();\n try {\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n const circuitEnode = circuit.getENode(branchingPoint.userData.enodeId);\n if (!circuitEnode) {\n throw new Error(\n `No enode with id ${branchingPoint.userData.enodeId} found in the circuit.`\n );\n }\n\n const modelPosition = worldToGridPosition(branchingPoint.position);\n const sourceType = branchingPoint.userData.sourceType as ENodeSourceType | undefined;\n circuitEnode.setPosition(modelPosition);\n circuitEnode.setSourceType(sourceType);\n\n if (emit) {\n this._controller.emit('circuitElementAction', {\n type: 'enode',\n action: 'edit',\n id: circuitEnode.id,\n error: null,\n data: {\n position: modelPosition,\n sourceType: sourceType,\n },\n });\n }\n return circuitEnode;\n } catch (error) {\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'enode',\n action: 'edit',\n id: branchingPoint.userData.id,\n error: error as Error,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n throw new Error((error as Error).message);\n }\n }\n\n /**\n * delete branching point in the core circuit model and emits the appropriate event.\n * @param enodeId - the branching point id\n * @throws Error\n * @return The circuit enode\n */\n saveDeleteBranchingPoint(enodeId: UUID): {\n deletedWires?: UUID[] | undefined;\n mergedWires?: UUID[] | undefined;\n newWire?: Wire | undefined;\n } {\n const circuit = this._controller.getCircuit();\n try {\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n const result = circuit.removeBranchingPoint(enodeId);\n\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'enode',\n action: 'delete',\n id: enodeId,\n error: null,\n data: {\n ...result,\n },\n };\n this._controller.emit('circuitElementAction', event);\n return result;\n } catch (error) {\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'enode',\n action: 'delete',\n id: enodeId,\n error: error as Error,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n throw new Error((error as Error).message);\n }\n }\n\n /**\n * add wire to the core circuit model and emits the appropriate event.\n * @param sourceEnodeId - the source enode ID\n * @param targetEnodeId - the target enode ID\n * @throws Error\n * @return The circuit wire\n */\n saveAddWire(sourceEnodeId: UUID, targetEnodeId: UUID) {\n const circuit = this._controller.getCircuit();\n try {\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n const addResult = circuit.addWire(sourceEnodeId, targetEnodeId);\n if (addResult instanceof Error) {\n throw new Error(addResult.message);\n }\n const wire = addResult as Wire;\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'wire',\n action: 'add',\n id: wire.id,\n error: null,\n data: {\n node1: wire.node1,\n node2: wire.node2,\n },\n };\n this._controller.emit('circuitElementAction', event);\n return wire;\n } catch (error) {\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'wire',\n action: 'add',\n id: undefined,\n error: error as Error,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n throw new Error((error as Error).message);\n }\n }\n\n /**\n * Save wire split operation to circuit model. Either :\n * - at a position, inserting a new branching point and two new wires replacing the deleted ones\n * - at an existing target enode, replacing the wire by two new wires connected to this enode\n * @param wireId - Wire to split\n * @param worldPosition - world Position for the new branching point : no effect if targetEnodeId provided\n * @param targetEnodeId - if provided, the existing enode to split the wire at\n * @returns Object containing the new branching point and two wires\n */\n saveSplitWire(\n wireId: UUID,\n worldPosition: Vector3,\n targetEnodeId: UUID | null = null\n ): { branchingPoint: ENode; wires: Wire[] } {\n const circuit = this._controller.getCircuit();\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n // Convert world position to grid position\n const gridPosition = worldToGridPosition(worldPosition);\n const result = circuit.splitWire(wireId, gridPosition, targetEnodeId);\n console.log(result);\n\n this._controller.emit('circuitElementAction', {\n type: 'wire',\n action: 'delete',\n id: wireId,\n });\n if (!targetEnodeId) {\n this._controller.emit('circuitElementAction', {\n type: 'enode',\n action: 'add',\n id: result.branchingPoint.id,\n });\n }\n for (const wire of result.wires) {\n this._controller.emit('circuitElementAction', {\n type: 'wire',\n action: 'add',\n id: wire.id,\n });\n }\n return result;\n }\n\n /**\n * delete wire to the core circuit model and emits the appropriate event.\n * @param wireId - the wire ID\n * @throws Error\n * @return The circuit wire\n */\n saveDeleteWire(wireId: UUID): void {\n const circuit = this._controller.getCircuit();\n try {\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n circuit.removeWire(wireId);\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'wire',\n action: 'delete',\n id: wireId,\n error: null,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n return;\n } catch (error) {\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'wire',\n action: 'delete',\n id: wireId,\n error: error as Error,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n }\n }\n\n /**\n * Used to commit wire edits (intermediate positions) to the core circuit model and emits the appropriate event.\n * If emit positions are also simplified before committing.\n * @param wireId - the wire ID\n * @param positions\n * @param emit\n * @return The circuit wire\n */\n saveEditWirePositions(\n wireId: UUID,\n positions: Array<{ x: number; y: number }>,\n emit: boolean = false\n ): Wire | undefined {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n const wire = circuit.getWire(wireId);\n if (!wire) return;\n\n const positionObjects = positions.map((p) => new Position(p.x, p.y));\n circuit.updateWireIntermediatePositions(wireId, positionObjects);\n\n if (emit) {\n circuit.simplifyWireIntermediatePositions(wireId);\n this._controller.emit('circuitElementAction', {\n type: 'wire',\n action: 'edit',\n id: wireId,\n error: null,\n data: {\n intermediatePositions: [...wire.intermediatePositions],\n },\n });\n }\n return wire;\n }\n\n /**\n * Used to simplify wire path in the core circuit model and emits the appropriate event.\n * Notably used when end enodes move is committed.\n * @param wireId - the wire ID\n * @return The circuit wire\n */\n saveSimplifyWirePositions(wireId: UUID): Wire | undefined {\n const circuit = this._controller.getCircuit();\n if (!circuit) return;\n const wire = circuit.getWire(wireId);\n if (!wire) return;\n\n circuit.simplifyWireIntermediatePositions(wireId);\n this._controller.emit('circuitElementAction', {\n type: 'wire',\n action: 'edit',\n id: wireId,\n error: null,\n data: {\n intermediatePositions: [...wire.intermediatePositions],\n },\n });\n return wire;\n }\n\n /**\n * Save ENode sourceType update (T011)\n * @param enodeId - ENode to update\n * @param sourceType - New sourceType value\n */\n saveEditENodeSourceType(enodeId: UUID, sourceType: ENodeSourceType | null): void {\n const circuit = this._controller.getCircuit();\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n\n circuit.updateENodeSourceType(enodeId, sourceType);\n\n this._controller.emit('circuitElementAction', {\n type: 'enode',\n action: 'edit',\n id: enodeId,\n error: null,\n data: {\n sourceType: sourceType,\n },\n });\n }\n\n /**\n * Add a component to the circuit model and emit the appropriate event\n * handles conversion of world position and rotation to circuit model values\n * @param type - Component type to add\n * @param position - world Position\n * @param rotation - world Rotation\n * @param config - optional initial component configuration\n * @param pinSources - optional array of ENode source types for each component pin\n * @returns The created Component\n * @throws Error if circuit is not available or component creation fails\n */\n saveAddComponent(\n type: ComponentType,\n position: Vector3,\n rotation: Euler,\n config?: Map<string, string> | undefined,\n pinSources?: Array<ENodeSourceType | undefined | null> | undefined\n ): Component {\n const circuit = this._controller.getCircuit();\n try {\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n // convert 3D world position to 2D grid position with Grid snapping\n const modelPosition = worldToGridPosition(position);\n const modelRotation = worldToGridRotation(rotation);\n const component = circuit.addComponent(type, modelPosition, modelRotation, config);\n\n if (pinSources) {\n for (const pinIdx in component.pins) {\n if (!pinSources[pinIdx]) continue;\n const customSource = pinSources[pinIdx];\n\n const cmpPinId = component.pins[pinIdx];\n if (!cmpPinId) continue;\n const pin = circuit.getENode(cmpPinId);\n if (!pin) continue;\n pin.setSourceType(customSource);\n }\n }\n\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'component',\n action: 'add',\n id: component.id,\n error: null,\n data: {\n componentId: component.id,\n componentType: type,\n position: modelPosition,\n rotation: modelRotation,\n config: config,\n pinSources: pinSources,\n },\n };\n this._controller.emit('circuitElementAction', event);\n return component;\n } catch (error) {\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'component',\n action: 'add',\n id: undefined,\n error: error as Error,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n throw new Error((error as Error).message);\n }\n }\n\n /**\n * Save edits made to a component in the circuit model and emit the appropriate event\n * @param componentId\n * @param visual\n * @param emit - should the event be emitted if commit OK (error event will always be)\n */\n saveEditComponent(componentId: UUID, visual: Object3D, emit: boolean = false): Component {\n // Logic to save the current state of the scene component into the core model\n const circuit = this._controller.getCircuit();\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n const component = circuit.getComponent(componentId);\n if (!component) {\n throw new Error(`Component with ID ${componentId} not found in the circuit.`);\n }\n\n const modelPosition = worldToGridPosition(visual.position);\n const modelRotation = worldToGridRotation(visual.rotation);\n component.setRotation(modelRotation);\n component.setPosition(modelPosition);\n\n if (emit) {\n this._controller.emit('circuitElementAction', {\n type: 'component',\n action: 'edit',\n id: componentId,\n error: null,\n data: {\n position: modelPosition,\n rotation: modelRotation,\n },\n });\n }\n\n return component;\n }\n\n /**\n * Save edits made to a component configuration in the circuit model and emit the appropriate event\n * @param componentId\n * @param parameters - updated configuration parameters\n */\n saveEditComponentConfig(componentId: UUID, parameters: Map<string, string>): Component {\n // Logic to save the current state of the scene component into the core model\n const circuit = this._controller.getCircuit();\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n const component = circuit.getComponent(componentId);\n if (!component) {\n throw new Error(`Component with ID ${componentId} not found in the circuit.`);\n }\n\n component.config = new Map([...component.config, ...parameters]);\n this._controller.emit('circuitElementAction', {\n type: 'component',\n action: 'edit',\n id: componentId,\n error: null,\n data: {\n config: component.config,\n },\n });\n return component;\n }\n\n /**\n * cycle component config and update visuals if necessary\n * have effect only on components that supports fast config cycle (used to invert logic or initial state of switches)\n * if component supports it, update the supported config item to the next value in the cycle\n * @param componentId\n * @returns object with hasChanged boolean and updated component\n * @throws Error if circuit is not available or component not found\n */\n cycleComponentConfig(componentId: UUID): { hasChanged: boolean; component: Component } {\n // Logic to save the current state of the scene component into the core model\n const circuit = this._controller.getCircuit();\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n const component = circuit.getComponent(componentId);\n if (!component) {\n throw new Error(`Component with ID ${componentId} not found in the circuit.`);\n }\n const config = component.config;\n switch (component.type) {\n case ComponentType.Switch:\n config.set('initialState', config.get('initialState') === 'open' ? 'closed' : 'open');\n this.saveEditComponentConfig(component.id, config);\n return { hasChanged: true, component: component };\n case ComponentType.Relay:\n config.set(\n 'activationLogic',\n config.get('activationLogic') === 'positive' ? 'negative' : 'positive'\n );\n this.saveEditComponentConfig(component.id, config);\n return { hasChanged: true, component: component };\n case ComponentType.Transistor:\n config.set(\n 'activationLogic',\n config.get('activationLogic') === 'positive' ? 'negative' : 'positive'\n );\n this.saveEditComponentConfig(component.id, config);\n return { hasChanged: true, component: component };\n default:\n return { hasChanged: false, component: component };\n }\n }\n\n /**\n * Delete a component from the circuit model and emit the appropriate event\n * @param componentId - UUID of the component to delete\n * @returns Information about removed wires and enodes\n * @throws Error if circuit is not available or component not found\n */\n saveDeleteComponent(componentId: UUID): {\n deletedWires: UUID[];\n deletedENodes: UUID[];\n } {\n const circuit = this._controller.getCircuit();\n try {\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n\n const component = circuit.getComponent(componentId);\n if (!component) {\n throw new Error(`Component with ID ${componentId} not found in the circuit.`);\n }\n\n // Remove component from circuit (this will also remove connected wires)\n const result: { deletedWires: UUID[]; deletedENodes: UUID[] } =\n circuit.removeComponent(componentId);\n\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'component',\n action: 'delete',\n id: componentId,\n error: null,\n data: { ...result },\n };\n this._controller.emit('circuitElementAction', event);\n\n return result;\n } catch (error) {\n const event: ControllerEventMap['circuitElementAction'] = {\n type: 'component',\n action: 'delete',\n id: componentId,\n error: error as Error,\n data: null,\n };\n this._controller.emit('circuitElementAction', event);\n throw new Error((error as Error).message);\n }\n }\n\n /**\n * Automatically adjust the circuit size and divisions based on positions of all core circuit elements.\n * @return if the size/division has been updated or not\n */\n saveAutoAdjustCircuitSize(): boolean {\n const circuit = this._controller.getCircuit();\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n\n const newSize = Math.max(10, circuit.getEnclosingSize(1));\n if (circuit.metadata.size === newSize) {\n return false; // no change\n }\n\n const divisions = computeDivisionsForSize(newSize);\n\n circuit.metadata.size = newSize;\n circuit.metadata.divisions = divisions;\n\n this._controller.emit('circuitMetadataEdition', {\n circuitName: circuit.name,\n data: {\n size: newSize,\n divisions: divisions,\n },\n });\n return true;\n }\n\n /**\n * Save current camera parameters, position and target into circuit metadata\n */\n saveCameraOptions(): void {\n const circuit = this._controller.getCircuit();\n if (!circuit) {\n throw new Error('No circuit available in the scene controller.');\n }\n const camera = this._controller.getCamera();\n if (!camera) {\n throw new Error('No camera available in the scene controller.');\n }\n const controls = this._controller.getControls();\n if (!controls) {\n throw new Error('No controls available in the scene controller.');\n }\n\n const options = new CameraOptions(\n new Position3D(camera.position.x, camera.position.y, camera.position.z),\n new Position3D(controls.target.x, controls.target.y, controls.target.z),\n camera.fov,\n camera.near,\n camera.far\n );\n circuit.metadata.cameraOptions = options;\n\n this._controller.emit('circuitMetadataEdition', {\n circuitName: circuit.name,\n data: {\n cameraOptions: options,\n },\n });\n return;\n }\n}\n","/**\n * Camera Utilities\n * @module scene/shared/utils/CameraUtils\n *\n * Helper functions for camera setup and management\n */\n\nimport * as THREE from 'three';\nimport { CameraOptions } from 'simple-circuit-engine/core';\n\n/**\n * Create a perspective camera with default or custom parameters\n *\n * @param options -\n * @param aspect - Camera aspect ratio (width / height)\n * @returns Configured PerspectiveCamera\n */\nexport function createPerspectiveCamera(\n aspect: number = 1,\n options: CameraOptions = new CameraOptions()\n): THREE.PerspectiveCamera {\n const camera = new THREE.PerspectiveCamera(options.fov, aspect, options.near, options.far);\n // Default camera position for circuit viewing\n const camPos = options.position;\n camera.position.set(camPos.x, camPos.y, camPos.z);\n const camTarget = options.lookAtPosition;\n camera.lookAt(camTarget.x, camTarget.y, camTarget.z);\n return camera;\n}\n\n/**\n * update camera position and target from options\n *\n * @param camera - Camera to configure\n * @param options\n */\nexport function updateCamera(camera: THREE.PerspectiveCamera, options: CameraOptions): void {\n camera.fov = options.fov;\n camera.near = options.near;\n camera.far = options.far;\n\n const camPos = options.position;\n camera.position.set(camPos.x, camPos.y, camPos.z);\n // NB : if controls are used, they may override the lookAt\n // then you need to update their controls separately\n const camTarget = options.lookAtPosition;\n camera.lookAt(camTarget.x, camTarget.y, camTarget.z);\n camera.updateProjectionMatrix();\n}\n","/**\n * Lighting Utilities\n * @module scene/shared/utils/LightingUtils\n *\n * Helper functions for setting up scene lighting\n */\n\nimport * as THREE from 'three';\n\n/**\n * Create an ambient light with default intensity\n *\n * @param color - Light color (hex)\n * @param intensity - Light intensity (0-1)\n * @returns AmbientLight\n */\nexport function createAmbientLight(\n color: number = 0xffffff,\n intensity: number = 0.6\n): THREE.AmbientLight {\n return new THREE.AmbientLight(color, intensity);\n}\n\n/**\n * Create a directional light with default positioning\n *\n * @param color - Light color (hex)\n * @param intensity - Light intensity\n * @param position - Light position\n * @returns DirectionalLight\n */\nexport function createDirectionalLight(\n color: number = 0xffffff,\n intensity: number = 0.8,\n position: THREE.Vector3 = new THREE.Vector3(10, 20, 10)\n): THREE.DirectionalLight {\n const light = new THREE.DirectionalLight(color, intensity);\n light.position.copy(position);\n return light;\n}\n\n/**\n * Setup standard scene lighting (ambient + directional)\n *\n * @param scene - Scene to add lights to\n * @returns Array of created lights\n */\nexport function setupSceneLights(scene: THREE.Scene): THREE.Light[] {\n const lights: THREE.Light[] = [];\n\n // Ambient light for base illumination\n const ambient = createAmbientLight(0xffffff, 0.6);\n scene.add(ambient);\n lights.push(ambient);\n\n // Main directional light from above\n const main = createDirectionalLight(0xffffff, 0.8, new THREE.Vector3(10, 20, 10));\n scene.add(main);\n lights.push(main);\n\n // Fill light from opposite side\n const fill = createDirectionalLight(0xffffff, 0.3, new THREE.Vector3(-10, 15, -10));\n scene.add(fill);\n lights.push(fill);\n\n return lights;\n}\n","/**\n * Three.js Layer Constants for Hitbox Organization\n * @module scene/shared/utils/LayerConstants\n *\n * Defines layer assignments for priority-based raycasting and rendering.\n */\n\n/**\n * Three.js layer assignments for hitbox meshes and rendering\n *\n * Layers enable priority-based raycasting by querying layers sequentially.\n * Lower layer numbers = higher priority for hover detection.\n *\n * @remarks\n * - Layer 0 is reserved for default visual rendering\n * - Hitbox layers (1-3) are invisible but raycastable\n * - Camera.layers should include only layer 0 for rendering\n * - Raycaster.layers is set per-query based on priority\n *\n * @example\n * ```typescript\n * import { HitboxLayers } from './LayerConstants';\n *\n * // Assign hitbox to component layer\n * hitboxMesh.layers.set(HitboxLayers.COMPONENT);\n *\n * // Raycast only enode hitboxes\n * raycaster.layers.set(HitboxLayers.ENODE);\n * ```\n */\nexport const HitboxLayers = {\n /** Default layer for visual rendering (do not use for hitboxes) */\n DEFAULT: 0,\n /** Enode hitboxes - highest hover priority */\n ENODE: 1,\n /** Component hitboxes - medium hover priority */\n COMPONENT: 2,\n /** Wire hitboxes - lowest hover priority */\n WIRE: 3,\n} as const;\n\nexport type HitboxLayerValue = (typeof HitboxLayers)[keyof typeof HitboxLayers];\n","/**\n * HoverManager Implementation\n * @module scene/shared/HoverManager\n *\n * Handles priority-based hover detection using Three.js Raycaster and Layers.\n * Implements priority: enode > component > wire\n */\n\nimport * as THREE from 'three';\nimport type { HoveredElement, HitboxUserData } from './types';\nimport { HitboxLayers } from './utils/LayerConstants';\n\n/**\n * Callback type for hover state changes\n */\nexport type HoverCallback = (\n element: HoveredElement | null,\n previousElement: HoveredElement | null\n) => void;\n\n/**\n * HoverManager Class\n *\n * Manages hover detection using Three.js Raycaster against hitbox layers.\n * Implements priority-based detection: enode > component > wire.\n */\nexport class HoverManager {\n private scene: THREE.Scene;\n private camera: THREE.Camera;\n private raycaster: THREE.Raycaster;\n private readonly groundPlane: THREE.Plane;\n private readonly groundPlanePosition = new THREE.Vector3();\n private currentlyHovered: HoveredElement | null = null;\n private callbacks: Set<HoverCallback> = new Set();\n private enabled: boolean = true;\n private initialized: boolean = false;\n private lastMouseX: number = 0;\n private lastMouseY: number = 0;\n private lastUpdateTime: number = 0;\n private throttleMs: number = 8; // ~120fps max update rate (performance optimization)\n\n /**\n * Create a new HoverManager\n *\n * @param scene - Three.js scene containing hitbox meshes\n * @param camera - Three.js camera for raycasting\n */\n constructor(scene: THREE.Scene, camera: THREE.Camera) {\n this.scene = scene;\n this.camera = camera;\n this.raycaster = new THREE.Raycaster();\n // Set up raycaster with Line2 threshold (in screen pixels)\n this.raycaster.params.Line2 = { threshold: 10 }; // 10px hover zone around line\n\n this.groundPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); // XZ plane at y=0\n }\n\n /**\n * Get the last computed ground plane position under the mouse\n *\n * @returns THREE.Vector3 position on ground plane\n */\n getGroundPlanePosition(): THREE.Vector3 {\n return this.groundPlanePosition;\n }\n\n /**\n * Update hover state based on normalized mouse coordinates\n * Also update the VERY IMPORTANT ground plane position used for CircuitManager cursorGroundPlanePosition\n *\n * Performs priority-based raycasting against hitbox layers.\n * If hover state changes, triggers onHoverChange callback.\n *\n * @param normalizedX - Mouse X in normalized HTML container coordinates [-1, 1]\n * @param normalizedY - Mouse Y in normalized HTML container coordinates [-1, 1]\n */\n updateFromMouse(normalizedX: number, normalizedY: number): void {\n if (!this.enabled) {\n return;\n }\n\n // Performance optimization: Throttle updates to max ~120fps (T033)\n const now = performance.now();\n if (now - this.lastUpdateTime < this.throttleMs) {\n return;\n }\n this.lastUpdateTime = now;\n\n // Store mouse position for refresh()\n this.lastMouseX = normalizedX;\n this.lastMouseY = normalizedY;\n\n // Setup raycaster\n this.raycaster.setFromCamera(new THREE.Vector2(normalizedX, normalizedY), this.camera);\n\n // VERY IMPORTANT: Update ground plane position so that controller cursorGroundPlanePosition queries work correctly\n this.raycaster.ray.intersectPlane(this.groundPlane, this.groundPlanePosition);\n\n // Try to find a hit in priority order: ENODE > COMPONENT > WIRE\n let hitElement: HoveredElement | null = null;\n\n // Priority 1: Check ENODE layer\n hitElement = this._raycastLayer(HitboxLayers.ENODE, 'enode', 'enodeHitbox');\n // disambiguation for very closed components (transistors)\n // if enode is a component pin, we check if the mouse is actually over the component hitbox too\n // if they differ we prioritize the component hitbox\n if (hitElement && hitElement.object3D.userData.componentId) {\n const componentHit = this._raycastLayer(\n HitboxLayers.COMPONENT,\n 'component',\n 'componentHitbox'\n );\n if (componentHit && componentHit.id !== hitElement.object3D.userData.componentId) {\n hitElement = componentHit;\n }\n }\n\n // Priority 2: Check COMPONENT layer\n if (!hitElement) {\n hitElement = this._raycastLayer(HitboxLayers.COMPONENT, 'component', 'componentHitbox');\n }\n\n // Priority 3: Check WIRE layer if no component hit\n if (!hitElement) {\n hitElement = this._raycastLayer(HitboxLayers.WIRE, 'wire', 'wire');\n }\n // Compare with current state and trigger callbacks if changed\n this._updateHoverState(hitElement);\n }\n\n /**\n * Force update hover state at current mouse position\n *\n * Useful after camera changes or scene updates to refresh hover state\n * without requiring a new mouse event.\n */\n refresh(): void {\n if (this.enabled) {\n this.updateFromMouse(this.lastMouseX, this.lastMouseY);\n }\n }\n\n /**\n * Clear current hover state\n *\n * Triggers unhover callback if an element was hovered.\n * Call this when mouse leaves the container.\n */\n clear(): void {\n this._updateHoverState(null);\n }\n\n /**\n * Get the currently hovered element\n *\n * @returns HoveredElement if something is hovered, null otherwise\n */\n getHoveredElement(): HoveredElement | null {\n return this.currentlyHovered;\n }\n\n /**\n * Register callback for hover state changes\n *\n * Callback is invoked when:\n * - Hover starts (element becomes non-null)\n * - Hover changes to different element\n * - Hover ends (element becomes null)\n *\n * @param callback - Function to call on hover state change\n */\n onHoverChange(callback: HoverCallback): void {\n this.callbacks.add(callback);\n }\n\n /**\n * Remove previously registered hover change callback\n *\n * @param callback - Same function reference passed to onHoverChange\n */\n offHoverChange(callback: HoverCallback): void {\n this.callbacks.delete(callback);\n }\n\n /**\n * Enable or disable hover detection\n *\n * When disabled, updateFromMouse() becomes a no-op.\n * Useful for temporarily disabling hover during drag operations.\n *\n * @param enabled - Whether to enable hover detection\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n if (!enabled) {\n // Clear hover state when disabling\n this.clear();\n }\n }\n\n /**\n * Check if hover detection is enabled\n *\n * @returns true if enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Set initialization state (to prevent double init)\n * @param initialized\n */\n setInitialized(initialized: boolean): void {\n this.initialized = initialized;\n }\n\n /**\n * Check if HoverManager is initialized (to prevent double init)\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * Clean up resources\n *\n * Removes all callbacks and clears state.\n * Call when disposing the scene controllerType.\n */\n dispose(): void {\n this.clear();\n this.callbacks.clear();\n this.initialized = false;\n }\n\n // ==========================================\n // Private Helper Methods\n // ==========================================\n\n /**\n * Perform raycasting on a specific layer and extract hit information\n *\n * @param layer - Hitbox layer number to raycast against\n * @param hoverableType - Type for HoveredElement\n * @param objectType - CircuitSceneObjectType for event payload\n * @returns HoveredElement if hit found, null otherwise\n */\n private _raycastLayer(\n layer: number,\n hoverableType: 'enode' | 'component' | 'wire',\n objectType: 'enodeHitbox' | 'componentHitbox' | 'wire'\n ): HoveredElement | null {\n // Configure raycaster to only check the specified layer\n this.raycaster.layers.set(layer);\n\n // Perform raycast (recursive to check all children)\n const intersections = this.raycaster.intersectObjects(this.scene.children, true);\n\n // Find first valid hit with proper userData\n for (const intersection of intersections) {\n const obj = intersection.object;\n const userData = obj.userData as HitboxUserData;\n\n // Validate userData has correct type\n if (userData && userData.type === objectType) {\n if (userData.hasOwnProperty('preview')) {\n continue; // Ignore preview hitboxes\n }\n // Extract element ID based on hitbox type\n let elementId: string;\n if (userData.type === 'enodeHitbox') {\n // For enode hitboxes, use componentId (the component that owns the pin)\n elementId = userData.enodeId;\n } else if (userData.type === 'componentHitbox') {\n elementId = userData.componentId;\n } else if (userData.type === 'wire') {\n elementId = userData.wireId;\n } else {\n continue;\n }\n\n return {\n id: elementId,\n type: hoverableType,\n objectType: objectType,\n object3D: obj,\n };\n }\n }\n\n return null;\n }\n\n /**\n * Update hover state and trigger callbacks if changed\n *\n * Compares new hit with currentlyHovered and only triggers callbacks on change.\n *\n * @param newHit - New hover element or null\n */\n private _updateHoverState(newHit: HoveredElement | null): void {\n // Check if state has changed\n const hasChanged = !this._isSameHover(this.currentlyHovered, newHit);\n\n if (hasChanged) {\n const previousHit = this.currentlyHovered;\n this.currentlyHovered = newHit;\n\n // Trigger all registered callbacks\n for (const callback of this.callbacks) {\n callback(newHit, previousHit);\n }\n }\n }\n\n /**\n * Compare two hover elements for equality\n *\n * @param a - First element\n * @param b - Second element\n * @returns true if both represent the same hover state\n */\n private _isSameHover(a: HoveredElement | null, b: HoveredElement | null): boolean {\n // Both null = same\n if (a === null && b === null) {\n return true;\n }\n\n // One null, one not = different\n if (a === null || b === null) {\n return false;\n }\n\n // Compare id and type\n return a.id === b.id && a.type === b.type;\n }\n}\n","/**\n * Branching Point Visual Factory\n * @module scene/shared/components/BranchingPointVisualFactory\n *\n * Creates cone-shaped visuals for branching point enodes with:\n * - SourceType-based color coding (white/red/blue)\n * - Hover/selection feedback via brightness shift\n * - Hitbox for raycasting on ENODE layer\n */\n\nimport * as THREE from 'three';\nimport { type ENodeSourceType, type ENode, ENodeType } from 'simple-circuit-engine/core';\nimport { HitboxLayers } from './utils/LayerConstants';\n\n/**\n * Factory for creating branching point visuals.\n *\n * Branching points are rendered as cones with colors indicating their sourceType:\n * - White (0xffffff): No source (null)\n * - Red (0xff0000): Voltage source\n * - Blue (0x0000ff): Current source\n *\n * Hover and selection states use brightness shift of the base color.\n */\nexport class BranchingPointVisualFactory {\n // Color constants\n private static readonly COLORS = {\n null: 0xffffff, // white - no source\n Voltage: 0xff0000, // red - voltage source\n Current: 0x0000ff, // blue - current source\n };\n\n private static readonly DEFAULT_HOVER_COLOR = 0x4488ff; // Yellow for hitbox hover feedback\n private static readonly HOVER_EMISSIVE = 0x4488ff; // Slight brightening on hover\n private static readonly SELECTED_EMISSIVE = 0xff8800; // More brightening on selection\n\n // Cone geometry dimensions\n private static readonly CONE_RADIUS = 0.3;\n private static readonly CONE_HEIGHT = 0.6;\n private static readonly CONE_SEGMENTS = 16;\n\n // Hitbox square (larger than visual for easier clicking)\n private static readonly HITBOX_SQUARE = 1;\n\n /**\n * Create visual representation for a branching point.\n * @param enode - The branching point ENode\n * @returns THREE.Group containing cone mesh and hitbox\n */\n createVisual(enode: ENode): THREE.Group {\n const group = new THREE.Group();\n group.name = ENodeType.BranchingPoint;\n // Set userData for raycasting identification\n group.userData = {\n type: 'enodeGroup',\n componentId: null,\n enodeId: enode.id,\n label: ENodeType.BranchingPoint,\n };\n\n // Hitbox (box, raycastable)\n const hitboxGeom = new THREE.BoxGeometry(\n BranchingPointVisualFactory.HITBOX_SQUARE,\n BranchingPointVisualFactory.HITBOX_SQUARE,\n BranchingPointVisualFactory.HITBOX_SQUARE\n );\n const hitbox = new THREE.Mesh(\n hitboxGeom,\n new THREE.MeshStandardMaterial({\n color: BranchingPointVisualFactory.DEFAULT_HOVER_COLOR,\n transparent: true,\n opacity: 0,\n })\n );\n hitbox.userData = {\n type: 'enodeHitbox',\n componentId: null,\n enodeId: enode.id,\n label: ENodeType.BranchingPoint,\n };\n hitbox.layers.set(HitboxLayers.ENODE);\n group.add(hitbox);\n\n // Create cone geometry\n const coneGeometry = new THREE.ConeGeometry(\n BranchingPointVisualFactory.CONE_RADIUS,\n BranchingPointVisualFactory.CONE_HEIGHT,\n BranchingPointVisualFactory.CONE_SEGMENTS\n );\n // Get color based on sourceType\n const color = this.getColorForSourceType(enode.source);\n // Create material with base color\n const coneMaterial = new THREE.MeshStandardMaterial({\n color,\n emissive: 0x000000,\n metalness: 0.3,\n roughness: 0.7,\n });\n\n // Create visual mesh\n const visual = new THREE.Mesh(coneGeometry, coneMaterial);\n visual.userData = {\n type: 'enode',\n componentId: null,\n enodeId: enode.id,\n label: ENodeType.BranchingPoint,\n };\n visual.position.set(0, 0.1, 0); // increase the height a little\n group.add(visual);\n\n return group;\n }\n\n /**\n * Update branching point object3D's visual to reflect sourceType change.\n * @param object3D - The branching point basis object3D (group)\n * @param sourceType - New source type\n */\n updateSourceType(object3D: THREE.Object3D, sourceType: ENodeSourceType | null): void {\n object3D.userData.sourceType = sourceType;\n const visual = object3D.children.find((child) => child.userData.type === 'enode') as\n | THREE.Mesh\n | undefined;\n\n if (visual && visual.material instanceof THREE.MeshStandardMaterial) {\n const newColor = this.getColorForSourceType(sourceType);\n visual.material.color.setHex(newColor);\n }\n }\n\n protected colorForElectricalState(state: 'current' | 'voltage' | 'vc' | 'idle'): number {\n switch (state) {\n case 'voltage':\n return 0xff0000; // Red\n case 'current':\n return 0x0000ff; // Blue\n case 'vc':\n return 0xcc00cc; // Magenta\n case 'idle':\n default:\n return 0x000000;\n }\n }\n\n /**\n * Apply hover object3D feedback.\n * @param object3D - The branching point basis object3D (group)\n */\n applyHover(object3D: THREE.Object3D): void {\n if (object3D.userData.isSelected) {\n // object is selected; skip hover visual\n return;\n }\n\n const visual = object3D.children.find((child) => child.userData.type === 'enode') as\n | THREE.Mesh\n | undefined;\n\n if (visual && visual.material instanceof THREE.MeshStandardMaterial) {\n visual.material.emissive.setHex(BranchingPointVisualFactory.HOVER_EMISSIVE);\n }\n }\n\n /**\n * Remove hover object3D feedback.\n * @param object3D - The branching point basis object3D (group)\n */\n removeHover(object3D: THREE.Object3D): void {\n if (object3D.userData.isSelected) {\n // object is selected; skip hover visual\n return;\n }\n\n let fallbackEmissive = 0x000000;\n if (object3D.userData.electricalState) {\n fallbackEmissive = this.colorForElectricalState(object3D.userData.electricalState);\n }\n\n const visual = object3D.children.find((child) => child.userData.type === 'enode') as\n | THREE.Mesh\n | undefined;\n\n if (visual && visual.material instanceof THREE.MeshStandardMaterial) {\n visual.material.emissive.setHex(fallbackEmissive);\n }\n }\n\n /**\n * Apply selection object3D feedback.\n * @param object3D - The branching point basis object3D (group)\n */\n applySelection(object3D: THREE.Object3D): void {\n const visual = object3D.children.find((child) => child.userData.type === 'enode') as\n | THREE.Mesh\n | undefined;\n\n if (visual && visual.material instanceof THREE.MeshStandardMaterial) {\n visual.material.emissive.setHex(BranchingPointVisualFactory.SELECTED_EMISSIVE);\n }\n object3D.userData.isSelected = true;\n }\n\n /**\n * Remove selection object3D feedback.\n * @param object3D - The branching point basis object3D (group)\n */\n removeSelection(object3D: THREE.Object3D): void {\n const visual = object3D.children.find((child) => child.userData.type === 'enode') as\n | THREE.Mesh\n | undefined;\n\n if (visual && visual.material instanceof THREE.MeshStandardMaterial) {\n visual.material.emissive.setHex(0x000000);\n }\n object3D.userData.isSelected = false;\n }\n\n /**\n * Get the base color for a sourceType.\n * @param sourceType - Source type (null, 'Voltage', or 'Current')\n * @returns Color hex value\n */\n private getColorForSourceType(sourceType: ENodeSourceType | null | undefined): number {\n if (!sourceType) {\n return BranchingPointVisualFactory.COLORS.null;\n }\n return BranchingPointVisualFactory.COLORS[sourceType];\n }\n}\n","/**\n * Material Utilities\n * @module scene/shared/utils/MaterialUtils\n *\n * Helper functions for creating and managing Three.js materials\n */\n\nimport * as THREE from 'three';\nimport { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';\n\n/**\n * Create a standard material with common defaults\n *\n * @param color - Base color (hex)\n * @param options - Additional material options\n * @returns MeshStandardMaterial\n */\nexport function createStandardMaterial(\n color: number,\n options: {\n emissive?: number;\n emissiveIntensity?: number;\n metalness?: number;\n roughness?: number;\n transparent?: boolean;\n opacity?: number;\n } = {}\n): THREE.MeshStandardMaterial {\n return new THREE.MeshStandardMaterial({\n color,\n emissive: options.emissive ?? 0x000000,\n emissiveIntensity: options.emissiveIntensity ?? 0,\n metalness: options.metalness ?? 0.3,\n roughness: options.roughness ?? 0.7,\n transparent: options.transparent ?? false,\n opacity: options.opacity ?? 1,\n });\n}\n\n/**\n * Create a material for wire lines\n *\n * @param color - Line color (hex)\n * @param linewidth - Line width (note: may not work on all platforms)\n * @returns LineBasicMaterial\n */\nexport function createLineMaterial(\n color: number = 0xffffff,\n linewidth: number = 1\n): THREE.LineBasicMaterial {\n return new THREE.LineBasicMaterial({\n color,\n linewidth,\n });\n}\n\n/**\n * Create a LineMaterial for Line2 rendering with consistent line width\n *\n * Note: Resolution must be set after creation using material.resolution.set(width, height)\n *\n * @param color - Line color (hex, default: 0xffffff/white)\n * @param linewidth - Line width in pixels (default: 2)\n * @returns LineMaterial for Line2 objects\n *\n * @example\n * ```typescript\n * const material = createLine2Material(0xffffff, 2);\n * material.resolution.set(window.innerWidth, window.innerHeight);\n * ```\n */\nexport function createLine2Material(color: number = 0xffffff, linewidth: number = 2): LineMaterial {\n return new LineMaterial({\n color,\n linewidth,\n });\n}\n\n/**\n * Update material state for component state changes\n *\n * @param material - Material to update\n * @param state - Component state data\n */\nexport function updateMaterialState(\n material: THREE.MeshStandardMaterial,\n state: {\n isActive?: boolean;\n isHighlighted?: boolean;\n customColor?: number;\n emissiveIntensity?: number;\n }\n): void {\n if (state.customColor !== undefined) {\n material.color.setHex(state.customColor);\n }\n\n if (state.isHighlighted) {\n material.emissive.setHex(0x00ff00);\n material.emissiveIntensity = 0.3;\n } else if (state.isActive) {\n material.emissive.setHex(material.color.getHex());\n material.emissiveIntensity = state.emissiveIntensity ?? 0.5;\n } else {\n material.emissive.setHex(0x000000);\n material.emissiveIntensity = 0;\n }\n}\n\n/**\n * Create a semi-transparent preview material\n *\n * @param baseColor - Base color\n * @param opacity - Transparency level (0-1)\n * @returns MeshStandardMaterial configured for preview\n */\nexport function createPreviewMaterial(\n baseColor: number,\n opacity: number = 0.5\n): THREE.MeshStandardMaterial {\n return new THREE.MeshStandardMaterial({\n color: baseColor,\n transparent: true,\n opacity,\n emissive: baseColor,\n emissiveIntensity: 0.2,\n });\n}\n\n/**\n * Create an error state material (for validation feedback)\n *\n * @returns MeshStandardMaterial in error state (red tint)\n */\nexport function createErrorMaterial(): THREE.MeshStandardMaterial {\n return new THREE.MeshStandardMaterial({\n color: 0xff0000,\n transparent: true,\n opacity: 0.6,\n emissive: 0xff0000,\n emissiveIntensity: 0.5,\n });\n}\n","/**\n * Wire Visual Manager\n * @module scene/shared/WireVisualManager\n *\n * Manages wire visual rendering with:\n * - Pin-accurate endpoints (derived from component visuals)\n * - Multi-segment rendering via intermediate positions\n * - Dynamic updates during component movement\n */\n\nimport * as THREE from 'three';\nimport { Line2 } from 'three/examples/jsm/lines/Line2.js';\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';\nimport { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';\nimport type { UUID, Wire, Circuit } from 'simple-circuit-engine/core';\nimport { ENodeType } from 'simple-circuit-engine/core';\n\nimport { createLine2Material } from './utils/MaterialUtils';\nimport type { WireMaterialState } from './types';\nimport { HitboxLayers } from './utils/LayerConstants';\nimport { gridToWorldPosition } from './utils/GeometryUtils';\n\n/**\n * Wire path representation for rendering\n */\nexport interface WirePath {\n /** Wire ID */\n wireId: UUID;\n\n /** Ordered points in world space (Three.js coordinates) */\n points: THREE.Vector3[];\n}\n\n/**\n * Delegation of CircuitController which handles wire visual rendering with proper pin targeting and dynamic updates.\n *\n * Key responsibilities:\n * - Create wire visuals with endpoints at actual pin positions\n * - Support multi-segment wires via intermediatePositions\n * - Update wires dynamically when components move/rotate\n * - Update wire materials for hover/selection states\n * - may add and remove wire and branching point object3Ds in the scene directly\n *\n * @example\n * ```typescript\n * const wireManager = new WireVisualManager();\n *\n * // Create wire visual\n * const line = wireManager.createOrUpdateWire(wire, circuit, scene, componentGroups);\n *\n * // Update wires when component moves\n * wireManager.updateWiresForComponent(componentId, circuit, componentGroups);\n * ```\n */\nexport class WireVisualManager {\n private containerWidth: number = 500;\n private containerHeight: number = 500;\n\n private _scene: THREE.Scene | null = null;\n private _camera: THREE.Camera | null = null;\n private _componentObject3Ds: Map<UUID, THREE.Object3D>;\n private _wireObject3Ds: Map<UUID, Line2>;\n private _container: HTMLElement | null = null;\n private _circuit: Circuit | null = null;\n\n //private _controller: AbstractCircuitController;\n /** Shared LineMaterials for all wires (memory efficient, consistent styling) */\n private wireMaterials: Map<WireMaterialState, LineMaterial> = new Map();\n /** Preview wire for wire creation mode */\n private previewWire: Line2 | null = null;\n\n constructor(componentObject3Ds: Map<UUID, THREE.Object3D>, wireObject3Ds: Map<UUID, Line2>) {\n this._componentObject3Ds = componentObject3Ds;\n this._wireObject3Ds = wireObject3Ds;\n // Create shared LineMaterial with default white color and 2px width\n this.wireMaterials = new Map([\n ['idle', createLine2Material(0xffffff, 2)],\n ['hovered', createLine2Material(0x40dfff, 4)],\n ['selected', createLine2Material(0xffaa00, 3)],\n ['voltage', createLine2Material(0xff0000, 3)], // Red for voltage only\n ['current', createLine2Material(0x0000ff, 3)], // Blue for current only\n ['vc', createLine2Material(0xcc00cc, 4)], // Magenta for both voltage and current\n ]);\n }\n\n setContainer(container: HTMLElement | null): void {\n this._container = container;\n }\n\n setSceneAndCamera(scene: THREE.Scene, camera: THREE.Camera): void {\n this._scene = scene;\n this._camera = camera;\n }\n\n setCircuit(circuit: Circuit | null): void {\n this._circuit = circuit;\n }\n\n /**\n * Set the resolution for LineMaterial rendering\n *\n * MUST be called after initialization and on window/container resize\n * for Line2 to render correctly.\n *\n * @param width - Viewport width in pixels\n * @param height - Viewport height in pixels\n *\n * @example\n * ```typescript\n * wireManager.setResolution(window.innerWidth, window.innerHeight);\n *\n * window.addEventListener('resize', () => {\n * wireManager.setResolution(window.innerWidth, window.innerHeight);\n * });\n * ```\n */\n setResolution(width: number, height: number): void {\n this.containerWidth = width;\n this.containerHeight = height;\n for (const material of this.wireMaterials.values()) {\n material.resolution.set(width, height);\n }\n }\n\n /**\n * Get the Line2 object for a wire\n *\n * @param wireId - Wire ID\n * @returns Line2 or undefined if not found or disposed\n */\n getWireLine(wireId: UUID): Line2 | undefined {\n return this._wireObject3Ds?.get(wireId);\n }\n\n /**\n * Check if a wire visual exists\n *\n * @param wireId - Wire ID\n * @returns true if wire visual exists, false if not found or disposed\n */\n hasWire(wireId: UUID): boolean {\n return this._wireObject3Ds?.has(wireId) ?? false;\n }\n\n /**\n * Get all wire IDs managed by this controllerType\n *\n * @returns Array of wire UUIDs, empty if disposed\n */\n getWireIds(): UUID[] {\n if (!this._wireObject3Ds) {\n return [];\n }\n return Array.from(this._wireObject3Ds.keys());\n }\n\n /**\n * Create or update the visual for a wire using model wire positions\n *\n * @param wire - Wire to render\n * @returns The created/updated Line2 object\n */\n createOrUpdateWire(wire: Wire): Line2 {\n if (!this._scene) {\n throw new Error('WireVisualManager scene is not set');\n }\n\n const wirePath = this.computeWirePath(wire);\n\n let line = this._wireObject3Ds.get(wire.id);\n\n if (line) {\n // Update existing line geometry\n const geometry = new LineGeometry();\n geometry.setFromPoints(wirePath.points);\n line.geometry.dispose();\n line.geometry = geometry;\n } else {\n // Create new Line2\n const geometry = new LineGeometry();\n geometry.setFromPoints(wirePath.points);\n line = new Line2(geometry, this.wireMaterials.get('idle'));\n line.userData = {\n type: 'wire',\n wireId: wire.id,\n electricalState: 'idle',\n };\n // Enable wire hitbox layer\n line.layers.enable(HitboxLayers.WIRE);\n this._wireObject3Ds.set(wire.id, line);\n // Adding to scene is directly done here\n this._scene.add(line);\n }\n return line;\n }\n\n /**\n * Update a specific wire's geometry\n *\n * @param wireId - Wire ID to update\n */\n updateWireById(wireId: UUID): void {\n const circuit = this._circuit!; // TODO handle null circuit\n\n const wire = circuit.getWire(wireId);\n if (wire) {\n this.createOrUpdateWire(wire);\n }\n }\n\n /**\n * Update all wires connected to a component\n *\n * Called when a component is moved or rotated to update wire endpoints.\n *\n * @param componentId - Component that moved\n */\n updateWiresForComponent(componentId: UUID): void {\n const circuit = this._circuit!; // TODO handle null circuit\n\n const component = circuit.getComponent(componentId);\n if (!component) return;\n\n // Find all wires connected to this component's pins\n const wireIdsToUpdate = new Set<UUID>();\n\n for (const pinId of component.pins) {\n const enode = circuit.getENode(pinId);\n if (enode) {\n for (const wireId of enode.wires) {\n wireIdsToUpdate.add(wireId);\n }\n }\n }\n\n // Update each wire\n for (const wireId of wireIdsToUpdate) {\n this.updateWireById(wireId);\n }\n }\n\n /**\n * visual hover and selection effects\n */\n\n /**\n * Apply hovered visual effect to a wire\n * @param wireId\n */\n applyHoveredVisual(wireId: UUID): void {\n const line = this._wireObject3Ds.get(wireId);\n if (!line) return;\n if (line.material === this.wireMaterials.get('selected')) return;\n\n line.material = this.wireMaterials.get('hovered')!;\n }\n\n removeHoveredVisual(wireId: UUID): void {\n const line = this._wireObject3Ds.get(wireId);\n if (!line) return;\n if (line.material !== this.wireMaterials.get('hovered')) return;\n\n line.material = this.wireMaterials.get(line.userData.electricalState || 'idle')!;\n }\n\n applySelectedVisual(wireId: UUID): void {\n const line = this._wireObject3Ds.get(wireId);\n if (!line) return;\n line.material = this.wireMaterials.get('selected')!;\n }\n\n removeSelectedVisual(wireId: UUID): void {\n const line = this._wireObject3Ds.get(wireId);\n if (!line) return;\n if (line.material !== this.wireMaterials.get('selected')) return;\n\n line.material = this.wireMaterials.get(line.userData.electricalState || 'idle')!;\n }\n\n /**\n * Apply electrical state material to a wire\n * Used during simulation to visualize voltage/current flow\n *\n * @param wireId - Wire ID to update\n * @param state - Material state: 'current', 'voltage', 'vc' (voltage and current) or 'idle'\n */\n applyElectricalState(wireId: UUID, state: 'current' | 'voltage' | 'vc' | 'idle'): void {\n const line = this._wireObject3Ds.get(wireId);\n if (!line) return;\n\n // set fallback visual state\n line.userData.electricalState = state;\n // Don't override selected/hovered states\n const currentMaterial = line.material;\n if (currentMaterial === this.wireMaterials.get('selected')) return;\n if (currentMaterial === this.wireMaterials.get('hovered')) return;\n\n line.material = this.wireMaterials.get(state)!;\n }\n\n /**\n * removal and dispose\n */\n\n /**\n * Remove a wire visual from the scene\n *\n * @param wireId - Wire ID to remove\n */\n removeWire(wireId: UUID): void {\n if (!this._scene) {\n throw new Error('WireVisualManager scene is not set');\n }\n\n const wireLines = this._wireObject3Ds;\n const scene = this._scene;\n\n const line = wireLines.get(wireId);\n if (line) {\n scene.remove(line);\n line.geometry.dispose();\n // Do NOT dispose material - it's shared across all wires\n wireLines.delete(wireId);\n }\n }\n\n /**\n * Clean up all managed wire visuals\n */\n dispose(): void {\n // Guard against multiple dispose calls\n if (!this._wireObject3Ds) {\n return;\n }\n\n const wireLines = this._wireObject3Ds;\n const scene = this._scene;\n for (const [_wireId, line] of wireLines) {\n if (scene) scene.remove(line);\n line.geometry.dispose();\n // Individual wire materials are NOT disposed here - only geometries\n }\n wireLines.clear();\n\n // Remove preview wire if it exists\n this.removePreviewWire();\n\n // Dispose shared material once during full cleanup\n for (const material of this.wireMaterials.values()) {\n material.dispose();\n }\n this.wireMaterials.clear();\n // dereference all\n this._scene = null;\n this._camera = null;\n this._container = null;\n this._circuit = null;\n // @ts-ignore\n this._componentObject3Ds = null;\n // @ts-ignore\n this._wireObject3Ds = null;\n }\n\n /**\n * Preview wire helpers\n */\n\n /**\n * Create a preview wire for wire creation mode.\n * @param startPosition - World position of wire start\n * @returns Line2 object for preview\n */\n createPreviewWire(startPosition: THREE.Vector3): Line2 {\n if (!this._scene) {\n throw new Error('WireVisualManager scene is not set');\n }\n\n // Remove any existing preview\n this.removePreviewWire();\n\n // Create preview line geometry with two points (start and end at same position initially)\n const geometry = new LineGeometry();\n geometry.setFromPoints([\n startPosition.clone(),\n startPosition.clone(),\n //startPosition.clone().add(new THREE.Vector3(5, 5, 5))\n ]);\n\n // Use a slightly different material for preview (dashed or lower opacity)\n const material = createLine2Material(0xcccccc, 3);\n material.opacity = 0.7;\n material.dashed = true;\n material.dashSize = 1;\n material.gapSize = 0.3;\n material.transparent = false;\n\n const previewLine = new Line2(geometry, material);\n previewLine.renderOrder = 100; // Render on top\n\n this.previewWire = previewLine;\n this.previewWire.userData = {\n startPosition: startPosition.clone(),\n };\n\n this._scene.add(previewLine);\n\n return previewLine;\n }\n\n /**\n * Update preview wire endpoint.\n * @param endPosition - World position of wire end\n */\n updatePreviewWire(endPosition: THREE.Vector3): void {\n if (!this.previewWire) {\n return;\n }\n\n const geometry = this.previewWire.geometry as LineGeometry;\n\n const startPosition = this.previewWire.userData.startPosition;\n\n geometry.setFromPoints([startPosition.clone(), endPosition.clone()]);\n }\n\n /**\n * Remove preview wire from scene.\n */\n removePreviewWire(): void {\n if (this._scene && this.previewWire) {\n this._scene.remove(this.previewWire);\n this.previewWire.geometry.dispose();\n (this.previewWire.material as LineMaterial).dispose();\n this.previewWire = null;\n }\n }\n\n /**\n * Intermediate points and position helpers\n */\n\n /**\n * Get pin world position by traversing component group\n *\n * @param enodeId - The pin's ENode ID\n * @param componentGroup - The component's Three.js group\n * @returns World position of the pin, or null if not found\n */\n getPinWorldPositionFromGroup(\n enodeId: UUID,\n componentGroup: THREE.Object3D\n ): THREE.Vector3 | null {\n const target = new THREE.Vector3();\n let found = false;\n\n componentGroup.traverse((child) => {\n if (found) return;\n\n // Look for enode visual or enodeGroup with matching ID\n if (\n child.userData.enodeId === enodeId ||\n (child.userData.type === 'enodeGroup' && child.userData.enodeId === enodeId)\n ) {\n child.getWorldPosition(target);\n found = true;\n }\n });\n\n return found ? target : null;\n }\n\n /**\n * Get insertion index for a new intermediate point on a wire (T058)\n * @param wireId - Wire ID\n * @param worldPosition - Position where user clicked\n * @returns Index where new point should be inserted\n */\n getInsertIndexForPosition(wireId: UUID, worldPosition: THREE.Vector3): number {\n const circuit = this._circuit;\n if (!circuit) return 0;\n\n const wire = circuit.getWire(wireId);\n if (!wire) return 0;\n\n // Get wire path\n const wirePath = this.computeWirePath(wire);\n const points = wirePath.points;\n\n // Find the segment closest to the click position\n let minDistance = Infinity;\n let insertIndex = 0;\n\n for (let i = 0; i < points.length - 1; i++) {\n const segmentStart = points[i];\n const segmentEnd = points[i + 1];\n\n if (!segmentStart || !segmentEnd) continue;\n\n // Project click position onto segment\n const segmentDir = new THREE.Vector3().subVectors(segmentEnd, segmentStart);\n const segmentLength = segmentDir.length();\n\n if (segmentLength === 0) continue;\n\n segmentDir.normalize();\n const toClick = new THREE.Vector3().subVectors(worldPosition, segmentStart);\n const projection = toClick.dot(segmentDir);\n const clampedProjection = Math.max(0, Math.min(segmentLength, projection));\n\n const closestPoint = segmentStart.clone().addScaledVector(segmentDir, clampedProjection);\n const distance = worldPosition.distanceTo(closestPoint);\n\n if (distance < minDistance) {\n minDistance = distance;\n insertIndex = i;\n }\n }\n\n return insertIndex;\n }\n\n /**\n * Find nearest intermediate point on a wire within proximity threshold (T057)\n * @param wireId - Wire ID to search\n * @param clientPos - Client position (event.clientX/Y) to test - will be converted to container-relative\n * @param thresholdPx - Proximity threshold in pixels (default: 10)\n * @returns Object with pointIndex and distance, or null if none found\n */\n findNearestIntermediatePoint(\n wireId: UUID,\n clientPos: THREE.Vector2,\n thresholdPx: number = 10\n ): { pointIndex: number; distance: number } | null {\n const circuit = this._circuit;\n if (!circuit) return null;\n\n const wire = circuit.getWire(wireId);\n if (!wire) return null;\n\n // Convert client coordinates to container-relative coordinates\n const containerRelativePos = this.clientToContainerCoords(clientPos);\n\n let nearestIndex = -1;\n let nearestDistance = Infinity;\n\n // Check each intermediate position\n for (let i = 0; i < wire.intermediatePositions.length; i++) {\n const pos = wire.intermediatePositions[i];\n if (!pos) continue;\n\n const worldPos = gridToWorldPosition(pos);\n const pointScreenPos = this.worldToScreen(worldPos);\n const distance = this.screenDistance(containerRelativePos, pointScreenPos);\n\n if (distance < thresholdPx && distance < nearestDistance) {\n nearestIndex = i;\n nearestDistance = distance;\n }\n }\n\n if (nearestIndex >= 0) {\n return { pointIndex: nearestIndex, distance: nearestDistance };\n }\n\n return null;\n }\n\n /**\n * Compute the full path for a wire including intermediate positions\n *\n * @param wire - Wire to compute path for\n * @returns WirePath with array of Vector3 points from start to end\n */\n computeWirePath(wire: Wire): WirePath {\n const circuit = this._circuit!; // TODO handle null circuit\n const componentObject3Ds = this._componentObject3Ds;\n\n const node1 = circuit.getENode(wire.node1);\n const node2 = circuit.getENode(wire.node2);\n\n if (!node1 || !node2) {\n throw new Error(`Wire ${wire.id} has invalid node references`);\n }\n\n // Get start position\n const startPos = this._getENodeWorldPosition(\n node1.id,\n node1.type,\n node1.component,\n circuit,\n componentObject3Ds\n );\n\n // Get end position\n const endPos = this._getENodeWorldPosition(\n node2.id,\n node2.type,\n node2.component,\n circuit,\n componentObject3Ds\n );\n\n // Build full path: start -> intermediate positions -> end\n const points: THREE.Vector3[] = [startPos];\n\n // Add intermediate positions (convert from grid to world coordinates)\n for (const pos of wire.intermediatePositions) {\n points.push(gridToWorldPosition(pos));\n }\n\n points.push(endPos);\n\n return { wireId: wire.id, points };\n }\n\n /**\n * private helpers\n */\n\n /**\n * Get the world position of an ENode (pin or branching point)\n *\n * For pins: Traverses component group to find pin visual and gets world position\n * For branching points: Converts grid position to world coordinates\n *\n * @param enodeId - The ENode ID\n * @param enodeType - Type of the ENode (Pin or BranchingPoint)\n * @param componentId - Parent component ID (for pins)\n * @param circuit - Circuit for position lookup\n * @param componentGroups - Map of component ID to Three.js objects\n * @returns World position as Vector3\n */\n private _getENodeWorldPosition(\n enodeId: UUID,\n enodeType: ENodeType,\n componentId: UUID | undefined,\n circuit: Circuit,\n componentGroups: Map<UUID, THREE.Object3D>\n ): THREE.Vector3 {\n if (enodeType === ENodeType.Pin && componentId) {\n const componentGroup = componentGroups.get(componentId);\n if (componentGroup) {\n const pinPosition = this.getPinWorldPositionFromGroup(enodeId, componentGroup);\n if (pinPosition) {\n return pinPosition;\n }\n }\n // Fallback to component center if pin not found in visual hierarchy\n // TODO: handles regularly when branching points are renderered as scene objects\n const enode = circuit.getENode(enodeId);\n if (enode) {\n return gridToWorldPosition(enode.getPosition(circuit));\n }\n }\n\n // Branching point or fallback: use ENode.getPosition()\n const enode = circuit.getENode(enodeId);\n if (!enode) {\n throw new Error(`ENode ${enodeId} not found`);\n }\n return gridToWorldPosition(enode.getPosition(circuit));\n }\n\n /**\n * Convert 3D world position to 2D screen position (T056)\n * @param worldPosition - World position as Vector3\n * @returns Screen position as Vector2\n */\n private worldToScreen(worldPosition: THREE.Vector3): THREE.Vector2 {\n if (!this._camera) {\n throw new Error('WireVisualManager camera is not set');\n }\n\n const camera = this._camera;\n\n const vector = worldPosition.clone();\n vector.project(camera);\n\n const widthHalf = this.containerWidth / 2;\n const heightHalf = this.containerHeight / 2;\n\n return new THREE.Vector2(\n vector.x * widthHalf + widthHalf,\n -(vector.y * heightHalf) + heightHalf\n );\n }\n\n /**\n * Calculate distance between two 2D screen positions (T056)\n * @param screenPos1 - First screen position\n * @param screenPos2 - Second screen position\n * @returns Distance in pixels\n */\n private screenDistance(screenPos1: THREE.Vector2, screenPos2: THREE.Vector2): number {\n return screenPos1.distanceTo(screenPos2);\n }\n\n /**\n * Convert client coordinates (event.clientX/Y) to container-relative coordinates\n * @param clientPos - Position in client/viewport coordinates\n * @returns Position relative to the container's top-left corner\n */\n private clientToContainerCoords(clientPos: THREE.Vector2): THREE.Vector2 {\n if (!this._container) {\n throw new Error('WireVisualManager container is not set');\n }\n const container = this._container;\n const rect = container.getBoundingClientRect();\n\n return new THREE.Vector2(clientPos.x - rect.left, clientPos.y - rect.top);\n }\n}\n","/**\n * Utility functions to provide default options for the 3D circuit scene controllers and engine\n * @module scene/shared/utils/Options\n */\n\nimport type { ControllerOptions, EngineOptions, MapControlsOptions } from '../types';\n\nexport function mapControlsOptions(\n options: MapControlsOptions | undefined = undefined\n): MapControlsOptions {\n const defaultOptions: MapControlsOptions = {\n enablePan: true,\n screenSpacePanning: true,\n enableZoom: true,\n enableRotate: true,\n enableDamping: true,\n dampingFactor: 0.5,\n minDistance: 1,\n maxDistance: 100,\n panSpeed: 1.0,\n zoomSpeed: 2.0,\n rotateSpeed: 1.0,\n };\n\n if (!options) return defaultOptions;\n return { ...defaultOptions, ...options };\n}\n\nexport function controllerOptions(\n options: ControllerOptions | undefined = undefined\n): ControllerOptions {\n const defaultOptions: ControllerOptions = {\n backgroundColor: 0x222230,\n colorCenterLine: 0xddddaa,\n colorGrid: 0x777777,\n defaultTool: 'build',\n mapControls: mapControlsOptions(),\n };\n\n if (!options) return defaultOptions;\n options.mapControls = mapControlsOptions(options.mapControls);\n return { ...defaultOptions, ...options };\n}\n\nexport function engineOptions(options: EngineOptions | undefined = undefined): EngineOptions {\n const defaultOptions: EngineOptions = {\n initialMode: 'edit',\n controllerOptions: controllerOptions(),\n runnerOptions: { enableHistory: false, historyLimit: 1 },\n };\n\n if (!options) return defaultOptions;\n options.controllerOptions = controllerOptions(options.controllerOptions);\n return { ...defaultOptions, ...options };\n}\n","/**\n * Controls utilities\n * @module scene/shared/utils/ControlsUtils\n */\n\nimport * as THREE from 'three';\nimport { MapControls } from 'three/addons/controls/MapControls.js';\nimport type { MapControlsOptions } from '../types';\nimport { mapControlsOptions } from './Options';\n\nexport function createMapControls(\n camera: THREE.PerspectiveCamera,\n container: HTMLElement,\n options: MapControlsOptions\n): MapControls {\n const controls = new MapControls(camera, container);\n options = mapControlsOptions(options);\n\n controls.enablePan = options.enablePan!;\n controls.screenSpacePanning = options.screenSpacePanning!;\n controls.enableZoom = options.enableZoom!;\n controls.enableRotate = options.enableRotate!;\n controls.enableDamping = options.enableDamping!;\n controls.dampingFactor = options.dampingFactor!;\n controls.minDistance = options.minDistance!;\n controls.maxDistance = options.maxDistance!;\n controls.panSpeed = options.panSpeed!;\n controls.zoomSpeed = options.zoomSpeed!;\n controls.rotateSpeed = options.rotateSpeed!;\n\n return controls;\n}\n","/**\n * Abstract Circuit Controller\n * @module scene/shared/AbstractCircuitController\n *\n * Base class for circuit visualization controllers.\n * Provides common Three.js scene management, camera controls, and hover detection.\n */\n\nimport * as THREE from 'three';\nimport { MapControls } from 'three/addons/controls/MapControls.js';\nimport type { UUID, Circuit } from 'simple-circuit-engine/core';\nimport { EventEmitter } from './EventEmitter';\nimport type { IFactoryRegistry } from './components/ComponentVisualFactory';\nimport type {\n ControllerEventMap,\n ControllerOptions,\n HoveredElement,\n HoverableType,\n HitboxUserData,\n WireHitboxUserData,\n ComponentHitboxUserData,\n EnodeHitboxUserData,\n SharedResources,\n} from './types';\nimport { createPerspectiveCamera, updateCamera } from './utils/CameraUtils';\nimport { setupSceneLights } from './utils/LightingUtils';\nimport { HoverManager } from './HoverManager';\nimport type { Line2 } from 'three/examples/jsm/lines/Line2.js';\nimport { BranchingPointVisualFactory } from './BranchingPointVisualFactory';\nimport { WireVisualManager } from './WireVisualManager';\nimport { createGridHelper } from './utils/GeometryUtils';\nimport { controllerOptions } from './utils/Options';\nimport { createMapControls } from './utils/ControlsUtils';\n\n/**\n * Abstract base class for circuit controllers.\n *\n * Provides common functionality for both static editing (CircuitController)\n * and live simulation (CircuitRunnerController) modes:\n * - Three.js scene, camera, and MapControls management\n * - Container lifecycle (initialize/dispose)\n * - Hover detection via HoverManager\n * - Visual object tracking maps\n *\n * Subclasses must implement:\n * - Circuit/CircuitRunner specific logic\n * - Visual creation and update methods\n * - Mode-specific features (editing tools or simulation interpolation)\n */\nexport abstract class AbstractCircuitController extends EventEmitter<ControllerEventMap> {\n // Container and Three.js core objects\n protected _container: HTMLElement | null = null;\n protected _scene: THREE.Scene | null = null;\n protected _grid: THREE.GridHelper | null = null;\n protected _camera: THREE.PerspectiveCamera | null = null;\n protected _mapControls: MapControls | null = null;\n\n // circuit being visualized\n protected _circuit: Circuit | null = null;\n\n // Wire visuals\n public readonly wireVisualManager: WireVisualManager;\n\n // State flags\n protected _initialized: boolean = false;\n protected _options: ControllerOptions | null;\n\n protected _active: boolean = false;\n protected _disposed: boolean = false;\n protected _gridHalfSize: number = 20;\n\n // Scene visual object factories - Wire visuals managed separately\n public readonly factoryRegistry: IFactoryRegistry;\n public readonly branchingPointVisualFactory: BranchingPointVisualFactory;\n\n // Scene objects tracking\n protected _componentObject3Ds: Map<UUID, THREE.Object3D> = new Map();\n protected _enodeObject3Ds: Map<UUID, THREE.Object3D> = new Map();\n protected _wireObject3Ds: Map<UUID, Line2> = new Map();\n\n // Hover system\n protected _hoverManager: HoverManager | null = null;\n protected _mouseMoveHandler: ((event: MouseEvent) => void) | null = null;\n protected _mouseLeaveHandler: ((event: MouseEvent) => void) | null = null;\n protected _mapControlsChangeHandler: (() => void) | null = null;\n\n // Shared resources injection\n protected _sharedResources: SharedResources | null = null;\n protected _useSharedResources: boolean = false;\n\n /**\n * Create a new circuit controller\n *\n * @param factoryRegistry - Component visual factory registry\n * @param sharedResources - Optional shared resources for facade pattern (CircuitEngine)\n * @throws {TypeError} If factoryRegistry is null/undefined\n */\n constructor(factoryRegistry: IFactoryRegistry, sharedResources?: SharedResources) {\n super();\n if (!factoryRegistry) {\n throw new TypeError('FactoryRegistry is required');\n }\n this._options = controllerOptions();\n\n // If shared resources provided, store them for use in initialize()\n if (sharedResources) {\n this._sharedResources = sharedResources;\n this._useSharedResources = true;\n this.factoryRegistry = sharedResources.factoryRegistry;\n this.branchingPointVisualFactory = sharedResources.branchingPointVisualFactory;\n this.wireVisualManager = sharedResources.wireVisualManager;\n } else {\n this._useSharedResources = false;\n this.factoryRegistry = factoryRegistry;\n this.branchingPointVisualFactory = new BranchingPointVisualFactory();\n this.wireVisualManager = new WireVisualManager(this._componentObject3Ds, this._wireObject3Ds);\n }\n }\n\n get componentObject3Ds(): Map<UUID, THREE.Object3D> {\n return this._componentObject3Ds;\n }\n\n get enodeObject3Ds(): Map<UUID, THREE.Object3D> {\n return this._enodeObject3Ds;\n }\n\n get wireObject3Ds(): Map<UUID, Line2> {\n return this._wireObject3Ds;\n }\n\n protected get grid(): THREE.GridHelper | null {\n if (this._useSharedResources) return this._sharedResources?.grid || null;\n return this._grid;\n }\n\n protected set grid(grid: THREE.GridHelper) {\n if (this._useSharedResources) {\n if (this._sharedResources) {\n this._sharedResources.grid = grid;\n }\n } else {\n this._grid = grid;\n }\n }\n\n // ==========================================\n // Initialization and Lifecycle\n // ==========================================\n\n /**\n * Initialize the controller with a DOM container.\n * Creates scene, camera, lights, MapControls, and HoverManager.\n *\n * When sharedResources were provided in constructor, uses those instead\n * of creating new resources. This enables the CircuitEngine facade pattern.\n *\n * @param container - HTMLElement to attach scene to\n * @param options - Optional configuration\n * @throws {TypeError} If container is not a valid HTMLElement\n * @throws {Error} If already initialized\n */\n initialize(container: HTMLElement, options?: ControllerOptions): void {\n if (this._initialized) {\n return; // Already initialized\n }\n options = controllerOptions(options);\n this._options = options;\n\n if (!container || !(container instanceof HTMLElement)) {\n const error = new TypeError('Container must be a valid HTMLElement');\n this.emitError(error);\n throw error;\n }\n\n try {\n this._container = container;\n\n if (this._useSharedResources && this._sharedResources) {\n // Use injected shared resources\n this._componentObject3Ds = this._sharedResources.componentObject3Ds;\n this._enodeObject3Ds = this._sharedResources.enodeObject3Ds;\n this._wireObject3Ds = this._sharedResources.wireObject3Ds;\n\n this._scene = this._sharedResources.scene;\n this._camera = this._sharedResources.camera;\n this._mapControls = this._sharedResources.mapControls;\n this._hoverManager = this._sharedResources.hoverManager;\n // Note: factoryRegistry, branchingPointVisualFactory and WireVisualManager are already set from constructor\n\n // Initialize WireVisualManager resolution (Line2 rendering)\n this.wireVisualManager.setResolution(\n this._container!.clientWidth,\n this._container!.clientHeight\n );\n\n // Setup hover change callback for this controller\n if (!this._hoverManager.isInitialized()) {\n this._initializeHoverManager();\n }\n // Setup mouse event callbacks\n this._setupMouseCallbacks();\n } else {\n // Create own resources (standalone mode)\n // Create scene\n this._scene = new THREE.Scene();\n this._scene.background = new THREE.Color(options.backgroundColor);\n // Add default sized grid\n this._grid = createGridHelper(10, 10, options.colorCenterLine!, options.colorGrid!);\n this._scene.add(this._grid);\n\n setupSceneLights(this._scene);\n\n // Create camera\n const aspect = container.clientWidth / container.clientHeight || 1;\n this._camera = createPerspectiveCamera(aspect);\n this._camera.layers.set(0); // main visual layer\n this._camera.layers.enable(1); // enode hover layer\n this._camera.layers.enable(2); // component hover layer\n // Initialize MapControls\n this._mapControls = createMapControls(this._camera, this._container, options.mapControls!);\n\n // Initialize WireVisualManager\n this.wireVisualManager.setContainer(this._container!);\n this.wireVisualManager.setResolution(\n this._container!.clientWidth,\n this._container!.clientHeight\n );\n this.wireVisualManager.setSceneAndCamera(this._scene, this._camera);\n\n // Create HoverManager instance\n this._hoverManager = new HoverManager(this._scene, this._camera);\n // Initialize HoverManager\n this._initializeHoverManager();\n // Setup mouse event callbacks\n this._setupMouseCallbacks();\n // in standalone mode set active\n this._active = true;\n }\n\n // Allow subclasses to perform additional initialization\n this.onInitialize(options);\n\n this._initialized = true;\n\n // Emit ready event\n this.emitReady();\n } catch (error) {\n const err = error as Error;\n this.emitError(err);\n throw error;\n }\n }\n\n /**\n * Hook for subclasses to perform additional initialization.\n * Called after base initialization but before emitting 'ready'.\n *\n * @param options - Controller options passed to initialize()\n */\n protected abstract onInitialize(options?: ControllerOptions): void;\n\n /**\n * Emit the ready event with controller-specific data.\n */\n protected abstract emitReady(): void;\n\n /**\n * Emit an error event.\n */\n protected emitError(error: Error): void {\n (this as EventEmitter<ControllerEventMap>).emit('error', {\n message: error.message,\n error,\n });\n }\n\n /**\n * Check that controller is initialized and not disposed.\n * @throws {Error} If not initialized or already disposed\n */\n protected _checkInitialized(): void {\n if (!this._initialized) {\n throw new Error('Controller not initialized. Call initialize() first.');\n }\n if (this._disposed) {\n throw new Error('Controller has been disposed');\n }\n }\n\n /**\n * Clean up all WebGL resources.\n * Disposes geometries, materials, controls, and clears event listeners.\n *\n * When using shared resources, does not dispose scene, camera, controls, or hover manager\n * as those are owned by the CircuitEngine facade.\n */\n dispose(): void {\n this._checkInitialized();\n\n try {\n // Allow subclasses to clean up first\n this.onDispose();\n\n // Remove DOM event listeners (always owned by this controller)\n if (this._container) {\n if (this._mouseMoveHandler) {\n this._container.removeEventListener('mousemove', this._mouseMoveHandler);\n this._mouseMoveHandler = null;\n }\n if (this._mouseLeaveHandler) {\n this._container.removeEventListener('mouseleave', this._mouseLeaveHandler);\n this._mouseLeaveHandler = null;\n }\n }\n\n // Only dispose resources we own (not shared ones)\n if (!this._useSharedResources) {\n // Dispose HoverManager\n if (this._hoverManager) {\n this._hoverManager.dispose();\n this._hoverManager = null;\n }\n\n // Remove all visuals\n this._removeAllVisuals();\n // clear grid\n if (this.grid) {\n this._scene!.remove(this.grid);\n this.grid.geometry.dispose();\n this.grid.dispose();\n this._grid = null;\n }\n\n // Clear tracking maps\n this._componentObject3Ds.clear();\n this._enodeObject3Ds.clear();\n this._wireObject3Ds.clear();\n\n // dispose own wireVisualManager\n this.wireVisualManager.dispose();\n\n // Dispose MapControls\n if (this._mapControls) {\n if (this._mapControlsChangeHandler) {\n this._mapControls.removeEventListener('change', this._mapControlsChangeHandler);\n this._mapControlsChangeHandler = null;\n }\n this._mapControls.dispose();\n this._mapControls = null;\n }\n } else {\n // When using shared resources, just clear our references\n // The CircuitEngine will handle actual disposal\n this._hoverManager = null;\n this._scene = null;\n this._camera = null;\n this._mapControls = null;\n this._grid = null;\n // Note: visual maps are shared, so we don't clear them\n }\n\n // Clear event listeners\n this.removeAllListeners();\n\n this._disposed = true;\n this._initialized = false;\n } catch (error) {\n const err = error as Error;\n this.emitError(err);\n throw error;\n }\n }\n\n /**\n * Hook for subclasses to perform cleanup before base dispose.\n */\n protected abstract onDispose(): void;\n\n /**\n * Remove all visual objects from scene.\n * Subclasses must implement to handle their specific wire types.\n */\n protected abstract _removeAllVisuals(): void;\n\n public setActive(active: boolean): void {\n this._active = active;\n this.onSetActive(active);\n }\n\n protected abstract onSetActive(active: boolean): void;\n\n /**\n * Set the current circuit to visualize or null to clear the scene\n * @param circuit\n */\n abstract setCircuit(circuit: Circuit | null): void;\n\n /**\n * Get the current circuit being visualized\n */\n getCircuit(): Circuit | null {\n return this._circuit;\n }\n\n protected abstract onSetCircuit(): void;\n\n /**\n * Loads a new circuit to visualize or null for clearing the scene\n * @param circuit\n */\n protected _setCircuit(circuit: Circuit | null): void {\n this._checkInitialized();\n if (circuit === this._circuit) return; // TODO : implement hash and equals methods in circuit to perform value equality check\n if (!!this._circuit) {\n // Clear all existing visuals\n this._removeAllVisuals();\n const oldCircuitName = this._circuit.metadata.name || 'Unnamed Circuit';\n this._circuit = null;\n this.wireVisualManager.setCircuit(null);\n this.emit('circuitCleared', { name: oldCircuitName });\n }\n // clear grid in standalone mode\n if (!this._useSharedResources && this._grid) {\n this._grid.geometry.dispose();\n this._grid.dispose();\n this._scene!.remove(this._grid);\n this._grid = null;\n }\n\n if (circuit !== null) {\n const options = this._options || controllerOptions();\n // Perform full update with new circuit\n this._circuit = circuit;\n this._scene!.name = this._circuit!.metadata.name || 'Circuit Scene';\n this.wireVisualManager.setCircuit(circuit);\n this._gridHalfSize = Math.ceil(circuit.metadata.size / 2);\n // in standalone mode update grid, camera and controls according to circuit metadata\n if (!this._useSharedResources) {\n this._grid = createGridHelper(\n circuit.metadata.size,\n circuit.metadata.divisions,\n options.colorCenterLine!,\n options.colorGrid!\n );\n this._scene!.add(this._grid);\n\n if (this._camera) {\n updateCamera(this._camera, circuit.metadata.cameraOptions);\n }\n\n if (this._mapControls) {\n const controls = this._mapControls;\n const target = circuit.metadata.cameraOptions.lookAtPosition;\n controls.target.set(target.x, target.y, target.z);\n }\n }\n this.onSetCircuit();\n this.emit('circuitLoaded', { name: this._circuit.metadata.name || 'Unnamed Circuit' });\n }\n }\n\n /**\n * get the object3D (Group for components and enodes, Line2 for wires) by hoverable type and id\n * @param type\n * @param id\n */\n getObject3D(type: HoverableType, id: UUID): THREE.Object3D | undefined {\n switch (type) {\n case 'component':\n return this._componentObject3Ds.get(id);\n case 'enode':\n return this._enodeObject3Ds.get(id);\n case 'wire':\n return this._wireObject3Ds.get(id);\n default:\n return undefined;\n }\n }\n\n /**\n * Get the MapControls instance for direct manipulation.\n */\n getControls(): MapControls | null {\n return this._mapControls;\n }\n\n // ==========================================\n // Hover System\n // ==========================================\n\n /**\n * Get the current cursor position on the ground plane (y=0) in world coordinates\n * The position is clamped within the circuit grid boundaries but not snapped to grid\n * @param bound - Whether to constrain position within grid boundaries\n */\n cursorGroundPlanePosition(bound: boolean = true): THREE.Vector3 {\n const vector = this._hoverManager!.getGroundPlanePosition().clone();\n if (bound) {\n vector.set(\n Math.min(Math.max(vector.x, -this._gridHalfSize), this._gridHalfSize),\n 0,\n Math.min(Math.max(vector.z, -this._gridHalfSize), this._gridHalfSize)\n );\n }\n return vector;\n }\n\n /**\n * Initialize HoverManager for hover detection\n *\n * @private\n */\n private _initializeHoverManager(): void {\n if (!this._hoverManager) {\n throw new Error('HoverManager must be constructed before initialization');\n }\n if (!this._container) {\n throw new Error('Container must be defined to initialize HoverManager');\n }\n\n // Track previous hover state for unhover events\n // let previousElement: {\n // objectId: UUID;\n // objectType: any;\n // userData: HitboxUserData;\n // } | null = null;\n\n const unhoverPreviousElement = (element: HoveredElement) => {\n if (element.objectType === 'enodeHitbox') {\n const userData = element.object3D.userData as EnodeHitboxUserData;\n const enodeId = userData.enodeId;\n if (!enodeId) {\n console.warn('Failed to apply unhover effect (missing enodeId)');\n return;\n }\n const enodeGroup = this._enodeObject3Ds.get(enodeId);\n if (!enodeGroup) {\n console.warn('Failed to apply unhover effect (enodeGroup not found)');\n return;\n }\n try {\n // Use BranchingPointVisualFactory for branching points (T024)\n if (!userData.componentId) {\n this.branchingPointVisualFactory.removeHover(enodeGroup);\n } else {\n this.factoryRegistry.getFallbackFactory().removePinHover(enodeGroup);\n }\n } catch (error) {\n console.warn('Failed to apply unhover effect:', error);\n }\n return;\n } else if (element.objectType === 'componentHitbox') {\n const userData = element.object3D.userData as ComponentHitboxUserData;\n const componentId = userData.componentId;\n if (!componentId) {\n console.warn('Failed to apply unhover effect (missing componentId)');\n return;\n }\n const componentGroup = this._componentObject3Ds.get(componentId);\n if (!componentGroup) {\n console.warn('Failed to apply unhover effect (componentGroup not found)');\n return;\n }\n try {\n const factory = this.factoryRegistry.get(userData.componentType);\n factory.removeHover(componentGroup);\n } catch (error) {\n console.warn('Failed to remove hover effect:', error);\n }\n return;\n } else if (element.objectType === 'wire') {\n const userData = element.object3D.userData as WireHitboxUserData;\n const wireId = userData.wireId;\n if (!wireId) {\n console.warn('Failed to apply unhover effect (missing wireId)');\n return;\n }\n const wire = this._wireObject3Ds.get(wireId);\n if (!wire) {\n console.warn('Failed to apply unhover effect (wire not found)');\n return;\n }\n this.wireVisualManager.removeHoveredVisual(wireId);\n }\n };\n\n const hoverElement = (element: HoveredElement) => {\n if (element.objectType === 'enodeHitbox') {\n const userData = element.object3D.userData as EnodeHitboxUserData;\n const enodeId = userData.enodeId;\n if (!enodeId) {\n console.warn('Failed to apply hover effect (missing enodeId)');\n return;\n }\n const enodeGroup = this._enodeObject3Ds.get(enodeId);\n if (!enodeGroup) {\n console.warn('Failed to apply hover effect (enodeGroup not found)');\n return;\n }\n try {\n // Use BranchingPointVisualFactory for branching points (T024)\n if (!userData.componentId) {\n this.branchingPointVisualFactory.applyHover(enodeGroup);\n } else {\n this.factoryRegistry.getFallbackFactory().applyPinHover(enodeGroup);\n }\n } catch (error) {\n console.warn('Failed to apply hover effect:', error);\n }\n return;\n } else if (element.objectType === 'componentHitbox') {\n const userData = element.object3D.userData as ComponentHitboxUserData;\n const componentId = userData.componentId;\n if (!componentId) {\n console.warn('Failed to apply hover effect (missing componentId)');\n return;\n }\n const componentGroup = this._componentObject3Ds.get(componentId);\n if (!componentGroup) {\n console.warn('Failed to apply hover effect (componentGroup not found)');\n return;\n }\n try {\n const factory = this.factoryRegistry.get(userData.componentType);\n factory.applyHover(componentGroup);\n } catch (error) {\n console.warn('Failed to apply hover effect:', error);\n }\n return;\n } else if (element.objectType === 'wire') {\n const userData = element.object3D.userData as WireHitboxUserData;\n const wireId = userData.wireId;\n if (!wireId) {\n console.warn('Failed to apply hover effect (missing wireId)');\n return;\n }\n const wire = this._wireObject3Ds.get(wireId);\n if (!wire) {\n console.warn('Failed to apply hover effect (wire not found)');\n return;\n }\n this.wireVisualManager.applyHoveredVisual(wireId);\n }\n };\n\n // Register callback to emit hover/unhover events\n this._hoverManager.onHoverChange((element, previousElement) => {\n // Emit unhover for previous element if it exists\n if (previousElement && (!element || element.id !== previousElement.id)) {\n unhoverPreviousElement(previousElement);\n this.emit('unhover', {\n objectId: previousElement.id,\n objectType: previousElement.objectType,\n userData: previousElement.object3D.userData as HitboxUserData,\n });\n previousElement = null;\n }\n\n // Emit hover for new element\n if (element) {\n hoverElement(element);\n this.emit('hover', {\n objectId: element.id,\n objectType: element.objectType,\n userData: element.object3D.userData as HitboxUserData,\n });\n }\n });\n\n // Setup MapControls 'change' listener to refresh hover on camera movement\n if (this._mapControls) {\n this._mapControlsChangeHandler = () => {\n if (this._hoverManager) {\n this._hoverManager.refresh();\n }\n };\n this._mapControls.addEventListener('change', this._mapControlsChangeHandler);\n }\n this._hoverManager.setInitialized(true);\n }\n\n protected _setupMouseCallbacks(): void {\n if (!this._hoverManager) {\n throw new Error('HoverManager must be constructed before setting up mouse callbacks');\n }\n if (!this._container) {\n throw new Error('Container must be defined to setup mouse callbacks');\n }\n\n // Setup mousemove event listener : must always be active so that current world position can be queried\n this._mouseMoveHandler = (event: MouseEvent) => {\n if (!this._active || !this._container || !this._hoverManager) return;\n const rect = this._container.getBoundingClientRect();\n const x = ((event.clientX - rect.left) / rect.width) * 2 - 1;\n const y = -((event.clientY - rect.top) / rect.height) * 2 + 1;\n const oldPosition = this.cursorGroundPlanePosition();\n this._hoverManager.updateFromMouse(x, y);\n const newPosition = this.cursorGroundPlanePosition();\n if (!newPosition.equals(oldPosition)) {\n // this important event will be used by tools such as BuildTool to update preview positions\n this.emit('gridPositionMove', newPosition);\n }\n };\n this._container.addEventListener('mousemove', this._mouseMoveHandler);\n\n // Setup mouseleave event listener\n this._mouseLeaveHandler = (_event: MouseEvent) => {\n if (this._hoverManager) {\n this._hoverManager.clear();\n }\n };\n this._container.addEventListener('mouseleave', this._mouseLeaveHandler);\n }\n\n /**\n * Get the currently hovered element.\n */\n getHoveredElement(): HoveredElement | null {\n return this._hoverManager?.getHoveredElement() ?? null;\n }\n\n /**\n * Enable or disable hover detection.\n */\n setHoverEnabled(enabled: boolean): void {\n this._hoverManager?.setEnabled(enabled);\n }\n\n /**\n * Check if hover detection is enabled.\n */\n isHoverEnabled(): boolean {\n return this._hoverManager?.isEnabled() ?? false;\n }\n\n // ==========================================\n // Getters\n // ==========================================\n\n /**\n * Get the Three.js scene for rendering.\n * @throws {Error} If not initialized\n */\n getScene(): THREE.Scene {\n this._checkInitialized();\n return this._scene!;\n }\n\n /**\n * Get the Three.js camera for rendering.\n * @throws {Error} If not initialized\n */\n getCamera(): THREE.PerspectiveCamera {\n this._checkInitialized();\n return this._camera!;\n }\n\n /**\n * Get the HTML container element.\n * @throws {Error} If not initialized\n */\n getContainer(): HTMLElement {\n this._checkInitialized();\n if (!this._container) {\n throw new Error('Container not initialized');\n }\n return this._container;\n }\n\n /**\n * Check if controller is initialized.\n */\n get isInitialized(): boolean {\n return this._initialized;\n }\n\n /**\n * Check if controller is disposed.\n */\n get isDisposed(): boolean {\n return this._disposed;\n }\n\n // ==========================================\n // Container Resize\n // ==========================================\n\n /**\n * event handler when the container size changes\n * Can override the container boundingClientRect size by providing width and height\n * - Update camera projection matrix\n * - Update viewport size for Line2 material resolution\n * Should be called when the container size changes (e.g., window resize)\n *\n * @param width - New width (optional, uses container size if not provided)\n * @param height - New height (optional, uses container size if not provided)\n */\n onContainerResize(width?: number, height?: number): void {\n if (!this._container) return;\n\n if (width === undefined || height === undefined) {\n const rect = this._container.getBoundingClientRect();\n width = rect.width;\n height = rect.height;\n }\n\n if (this._camera) {\n this._camera.aspect = width / height;\n this._camera.updateProjectionMatrix();\n }\n this.wireVisualManager.setResolution(width, height);\n\n // Allow subclasses to handle resize\n this.onResize(width, height);\n }\n\n /**\n * Hook for subclasses to handle container resize.\n */\n protected onResize(_width: number, _height: number): void {\n // Default: no-op, subclasses can override\n }\n}\n","/**\n * lil-gui\n * https://lil-gui.georgealways.com\n * @version 0.21.0\n * @author George Michael Brower\n * @license MIT\n */\n\n/**\n * Base class for all controllers.\n */\nclass Controller {\n\n\tconstructor( parent, object, property, className, elementType = 'div' ) {\n\n\t\t/**\n\t\t * The GUI that contains this controller.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * The object this controller will modify.\n\t\t * @type {object}\n\t\t */\n\t\tthis.object = object;\n\n\t\t/**\n\t\t * The name of the property to control.\n\t\t * @type {string}\n\t\t */\n\t\tthis.property = property;\n\n\t\t/**\n\t\t * Used to determine if the controller is disabled.\n\t\t * Use `controller.disable( true|false )` to modify this value.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._disabled = false;\n\n\t\t/**\n\t\t * Used to determine if the Controller is hidden.\n\t\t * Use `controller.show()` or `controller.hide()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._hidden = false;\n\n\t\t/**\n\t\t * The value of `object[ property ]` when the controller was created.\n\t\t * @type {any}\n\t\t */\n\t\tthis.initialValue = this.getValue();\n\n\t\t/**\n\t\t * The outermost container DOM element for this controller.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.domElement = document.createElement( elementType );\n\t\tthis.domElement.classList.add( 'lil-controller' );\n\t\tthis.domElement.classList.add( className );\n\n\t\t/**\n\t\t * The DOM element that contains the controller's name.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$name = document.createElement( 'div' );\n\t\tthis.$name.classList.add( 'lil-name' );\n\n\t\tController.nextNameID = Controller.nextNameID || 0;\n\t\tthis.$name.id = `lil-gui-name-${++Controller.nextNameID}`;\n\n\t\t/**\n\t\t * The DOM element that contains the controller's \"widget\" (which differs by controller type).\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$widget = document.createElement( 'div' );\n\t\tthis.$widget.classList.add( 'lil-widget' );\n\n\t\t/**\n\t\t * The DOM element that receives the disabled attribute when using disable().\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$disable = this.$widget;\n\n\t\tthis.domElement.appendChild( this.$name );\n\t\tthis.domElement.appendChild( this.$widget );\n\n\t\t// Don't fire global key events while typing in a controller\n\t\tthis.domElement.addEventListener( 'keydown', e => e.stopPropagation() );\n\t\tthis.domElement.addEventListener( 'keyup', e => e.stopPropagation() );\n\n\t\tthis.parent.children.push( this );\n\t\tthis.parent.controllers.push( this );\n\n\t\tthis.parent.$children.appendChild( this.domElement );\n\n\t\tthis._listenCallback = this._listenCallback.bind( this );\n\n\t\tthis.name( property );\n\n\t}\n\n\t/**\n\t * Sets the name of the controller and its label in the GUI.\n\t * @param {string} name\n\t * @returns {this}\n\t */\n\tname( name ) {\n\t\t/**\n\t\t * The controller's name. Use `controller.name( 'Name' )` to modify this value.\n\t\t * @type {string}\n\t\t */\n\t\tthis._name = name;\n\t\tthis.$name.textContent = name;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pass a function to be called whenever the value is modified by this controller.\n\t * The function receives the new value as its first parameter. The value of `this` will be the\n\t * controller.\n\t *\n\t * For function controllers, the `onChange` callback will be fired on click, after the function\n\t * executes.\n\t * @param {Function} callback\n\t * @returns {this}\n\t * @example\n\t * const controller = gui.add( object, 'property' );\n\t *\n\t * controller.onChange( function( v ) {\n\t * \tconsole.log( 'The value is now ' + v );\n\t * \tconsole.assert( this === controller );\n\t * } );\n\t */\n\tonChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onChange` events. Don't modify this value directly.\n\t\t * Use the `controller.onChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onChange = callback;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls the onChange methods of this controller and its parent GUI.\n\t * @protected\n\t */\n\t_callOnChange() {\n\n\t\tthis.parent._callOnChange( this );\n\n\t\tif ( this._onChange !== undefined ) {\n\t\t\tthis._onChange.call( this, this.getValue() );\n\t\t}\n\n\t\tthis._changed = true;\n\n\t}\n\n\t/**\n\t * Pass a function to be called after this controller has been modified and loses focus.\n\t * @param {Function} callback\n\t * @returns {this}\n\t * @example\n\t * const controller = gui.add( object, 'property' );\n\t *\n\t * controller.onFinishChange( function( v ) {\n\t * \tconsole.log( 'Changes complete: ' + v );\n\t * \tconsole.assert( this === controller );\n\t * } );\n\t */\n\tonFinishChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onFinishChange` events. Don't modify this value\n\t\t * directly. Use the `controller.onFinishChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onFinishChange = callback;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Should be called by Controller when its widgets lose focus.\n\t * @protected\n\t */\n\t_callOnFinishChange() {\n\n\t\tif ( this._changed ) {\n\n\t\t\tthis.parent._callOnFinishChange( this );\n\n\t\t\tif ( this._onFinishChange !== undefined ) {\n\t\t\t\tthis._onFinishChange.call( this, this.getValue() );\n\t\t\t}\n\n\t\t}\n\n\t\tthis._changed = false;\n\n\t}\n\n\t/**\n\t * Sets the controller back to its initial value.\n\t * @returns {this}\n\t */\n\treset() {\n\t\tthis.setValue( this.initialValue );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Enables this controller.\n\t * @param {boolean} enabled\n\t * @returns {this}\n\t * @example\n\t * controller.enable();\n\t * controller.enable( false ); // disable\n\t * controller.enable( controller._disabled ); // toggle\n\t */\n\tenable( enabled = true ) {\n\t\treturn this.disable( !enabled );\n\t}\n\n\t/**\n\t * Disables this controller.\n\t * @param {boolean} disabled\n\t * @returns {this}\n\t * @example\n\t * controller.disable();\n\t * controller.disable( false ); // enable\n\t * controller.disable( !controller._disabled ); // toggle\n\t */\n\tdisable( disabled = true ) {\n\n\t\tif ( disabled === this._disabled ) return this;\n\n\t\tthis._disabled = disabled;\n\n\t\tthis.domElement.classList.toggle( 'lil-disabled', disabled );\n\t\tthis.$disable.toggleAttribute( 'disabled', disabled );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Shows the Controller after it's been hidden.\n\t * @param {boolean} show\n\t * @returns {this}\n\t * @example\n\t * controller.show();\n\t * controller.show( false ); // hide\n\t * controller.show( controller._hidden ); // toggle\n\t */\n\tshow( show = true ) {\n\n\t\tthis._hidden = !show;\n\n\t\tthis.domElement.style.display = this._hidden ? 'none' : '';\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Hides the Controller.\n\t * @returns {this}\n\t */\n\thide() {\n\t\treturn this.show( false );\n\t}\n\n\t/**\n\t * Changes this controller into a dropdown of options.\n\t *\n\t * Calling this method on an option controller will simply update the options. However, if this\n\t * controller was not already an option controller, old references to this controller are\n\t * destroyed, and a new controller is added to the end of the GUI.\n\t * @example\n\t * // safe usage\n\t *\n\t * gui.add( obj, 'prop1' ).options( [ 'a', 'b', 'c' ] );\n\t * gui.add( obj, 'prop2' ).options( { Big: 10, Small: 1 } );\n\t * gui.add( obj, 'prop3' );\n\t *\n\t * // danger\n\t *\n\t * const ctrl1 = gui.add( obj, 'prop1' );\n\t * gui.add( obj, 'prop2' );\n\t *\n\t * // calling options out of order adds a new controller to the end...\n\t * const ctrl2 = ctrl1.options( [ 'a', 'b', 'c' ] );\n\t *\n\t * // ...and ctrl1 now references a controller that doesn't exist\n\t * assert( ctrl2 !== ctrl1 )\n\t * @param {object|Array} options\n\t * @returns {Controller}\n\t */\n\toptions( options ) {\n\t\tconst controller = this.parent.add( this.object, this.property, options );\n\t\tcontroller.name( this._name );\n\t\tthis.destroy();\n\t\treturn controller;\n\t}\n\n\t/**\n\t * Sets the minimum value. Only works on number controllers.\n\t * @param {number} min\n\t * @returns {this}\n\t */\n\tmin( min ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum value. Only works on number controllers.\n\t * @param {number} max\n\t * @returns {this}\n\t */\n\tmax( max ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Values set by this controller will be rounded to multiples of `step`. Only works on number\n\t * controllers.\n\t * @param {number} step\n\t * @returns {this}\n\t */\n\tstep( step ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Rounds the displayed value to a fixed number of decimals, without affecting the actual value\n\t * like `step()`. Only works on number controllers.\n\t * @example\n\t * gui.add( object, 'property' ).listen().decimals( 4 );\n\t * @param {number} decimals\n\t * @returns {this}\n\t */\n\tdecimals( decimals ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls `updateDisplay()` every animation frame. Pass `false` to stop listening.\n\t * @param {boolean} listen\n\t * @returns {this}\n\t */\n\tlisten( listen = true ) {\n\n\t\t/**\n\t\t * Used to determine if the controller is currently listening. Don't modify this value\n\t\t * directly. Use the `controller.listen( true|false )` method instead.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._listening = listen;\n\n\t\tif ( this._listenCallbackID !== undefined ) {\n\t\t\tcancelAnimationFrame( this._listenCallbackID );\n\t\t\tthis._listenCallbackID = undefined;\n\t\t}\n\n\t\tif ( this._listening ) {\n\t\t\tthis._listenCallback();\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t_listenCallback() {\n\n\t\tthis._listenCallbackID = requestAnimationFrame( this._listenCallback );\n\n\t\t// To prevent framerate loss, make sure the value has changed before updating the display.\n\t\t// Note: save() is used here instead of getValue() only because of ColorController. The !== operator\n\t\t// won't work for color objects or arrays, but ColorController.save() always returns a string.\n\n\t\tconst curValue = this.save();\n\n\t\tif ( curValue !== this._listenPrevValue ) {\n\t\t\tthis.updateDisplay();\n\t\t}\n\n\t\tthis._listenPrevValue = curValue;\n\n\t}\n\n\t/**\n\t * Returns `object[ property ]`.\n\t * @returns {any}\n\t */\n\tgetValue() {\n\t\treturn this.object[ this.property ];\n\t}\n\n\t/**\n\t * Sets the value of `object[ property ]`, invokes any `onChange` handlers and updates the display.\n\t * @param {any} value\n\t * @returns {this}\n\t */\n\tsetValue( value ) {\n\n\t\tif ( this.getValue() !== value ) {\n\n\t\t\tthis.object[ this.property ] = value;\n\t\t\tthis._callOnChange();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Updates the display to keep it in sync with the current value. Useful for updating your\n\t * controllers when their values have been modified outside of the GUI.\n\t * @returns {this}\n\t */\n\tupdateDisplay() {\n\t\treturn this;\n\t}\n\n\tload( value ) {\n\t\tthis.setValue( value );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\tsave() {\n\t\treturn this.getValue();\n\t}\n\n\t/**\n\t * Destroys this controller and removes it from the parent GUI.\n\t */\n\tdestroy() {\n\t\tthis.listen( false );\n\t\tthis.parent.children.splice( this.parent.children.indexOf( this ), 1 );\n\t\tthis.parent.controllers.splice( this.parent.controllers.indexOf( this ), 1 );\n\t\tthis.parent.$children.removeChild( this.domElement );\n\t}\n\n}\n\nclass BooleanController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'lil-boolean', 'label' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'checkbox' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$input.addEventListener( 'change', () => {\n\t\t\tthis.setValue( this.$input.checked );\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$disable = this.$input;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.checked = this.getValue();\n\t\treturn this;\n\t}\n\n}\n\nfunction normalizeColorString( string ) {\n\n\tlet match, result;\n\n\tif ( match = string.match( /(#|0x)?([a-f0-9]{6})/i ) ) {\n\n\t\tresult = match[ 2 ];\n\n\t} else if ( match = string.match( /rgb\\(\\s*(\\d*)\\s*,\\s*(\\d*)\\s*,\\s*(\\d*)\\s*\\)/ ) ) {\n\n\t\tresult = parseInt( match[ 1 ] ).toString( 16 ).padStart( 2, 0 )\n\t\t\t+ parseInt( match[ 2 ] ).toString( 16 ).padStart( 2, 0 )\n\t\t\t+ parseInt( match[ 3 ] ).toString( 16 ).padStart( 2, 0 );\n\n\t} else if ( match = string.match( /^#?([a-f0-9])([a-f0-9])([a-f0-9])$/i ) ) {\n\n\t\tresult = match[ 1 ] + match[ 1 ] + match[ 2 ] + match[ 2 ] + match[ 3 ] + match[ 3 ];\n\n\t}\n\n\tif ( result ) {\n\t\treturn '#' + result;\n\t}\n\n\treturn false;\n\n}\n\nconst STRING = {\n\tisPrimitive: true,\n\tmatch: v => typeof v === 'string',\n\tfromHexString: normalizeColorString,\n\ttoHexString: normalizeColorString\n};\n\nconst INT = {\n\tisPrimitive: true,\n\tmatch: v => typeof v === 'number',\n\tfromHexString: string => parseInt( string.substring( 1 ), 16 ),\n\ttoHexString: value => '#' + value.toString( 16 ).padStart( 6, 0 )\n};\n\nconst ARRAY = {\n\tisPrimitive: false,\n\tmatch: v => Array.isArray( v ) || ArrayBuffer.isView( v ),\n\tfromHexString( string, target, rgbScale = 1 ) {\n\n\t\tconst int = INT.fromHexString( string );\n\n\t\ttarget[ 0 ] = ( int >> 16 & 255 ) / 255 * rgbScale;\n\t\ttarget[ 1 ] = ( int >> 8 & 255 ) / 255 * rgbScale;\n\t\ttarget[ 2 ] = ( int & 255 ) / 255 * rgbScale;\n\n\t},\n\ttoHexString( [ r, g, b ], rgbScale = 1 ) {\n\n\t\trgbScale = 255 / rgbScale;\n\n\t\tconst int = r * rgbScale << 16 ^\n\t\t\t g * rgbScale << 8 ^\n\t\t\t b * rgbScale << 0;\n\n\t\treturn INT.toHexString( int );\n\n\t}\n};\n\nconst OBJECT = {\n\tisPrimitive: false,\n\tmatch: v => Object( v ) === v,\n\tfromHexString( string, target, rgbScale = 1 ) {\n\n\t\tconst int = INT.fromHexString( string );\n\n\t\ttarget.r = ( int >> 16 & 255 ) / 255 * rgbScale;\n\t\ttarget.g = ( int >> 8 & 255 ) / 255 * rgbScale;\n\t\ttarget.b = ( int & 255 ) / 255 * rgbScale;\n\n\t},\n\ttoHexString( { r, g, b }, rgbScale = 1 ) {\n\n\t\trgbScale = 255 / rgbScale;\n\n\t\tconst int = r * rgbScale << 16 ^\n\t\t\t g * rgbScale << 8 ^\n\t\t\t b * rgbScale << 0;\n\n\t\treturn INT.toHexString( int );\n\n\t}\n};\n\nconst FORMATS = [ STRING, INT, ARRAY, OBJECT ];\n\nfunction getColorFormat( value ) {\n\treturn FORMATS.find( format => format.match( value ) );\n}\n\nclass ColorController extends Controller {\n\n\tconstructor( parent, object, property, rgbScale ) {\n\n\t\tsuper( parent, object, property, 'lil-color' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'color' );\n\t\tthis.$input.setAttribute( 'tabindex', -1 );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$text = document.createElement( 'input' );\n\t\tthis.$text.setAttribute( 'type', 'text' );\n\t\tthis.$text.setAttribute( 'spellcheck', 'false' );\n\t\tthis.$text.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$display = document.createElement( 'div' );\n\t\tthis.$display.classList.add( 'lil-display' );\n\n\t\tthis.$display.appendChild( this.$input );\n\t\tthis.$widget.appendChild( this.$display );\n\t\tthis.$widget.appendChild( this.$text );\n\n\t\tthis._format = getColorFormat( this.initialValue );\n\t\tthis._rgbScale = rgbScale;\n\n\t\tthis._initialValueHexString = this.save();\n\t\tthis._textFocused = false;\n\n\t\tthis.$input.addEventListener( 'input', () => {\n\t\t\tthis._setValueFromHexString( this.$input.value );\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'blur', () => {\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'input', () => {\n\t\t\tconst tryParse = normalizeColorString( this.$text.value );\n\t\t\tif ( tryParse ) {\n\t\t\t\tthis._setValueFromHexString( tryParse );\n\t\t\t}\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'focus', () => {\n\t\t\tthis._textFocused = true;\n\t\t\tthis.$text.select();\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'blur', () => {\n\t\t\tthis._textFocused = false;\n\t\t\tthis.updateDisplay();\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$disable = this.$text;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\treset() {\n\t\tthis._setValueFromHexString( this._initialValueHexString );\n\t\treturn this;\n\t}\n\n\t_setValueFromHexString( value ) {\n\n\t\tif ( this._format.isPrimitive ) {\n\n\t\t\tconst newValue = this._format.fromHexString( value );\n\t\t\tthis.setValue( newValue );\n\n\t\t} else {\n\n\t\t\tthis._format.fromHexString( value, this.getValue(), this._rgbScale );\n\t\t\tthis._callOnChange();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t}\n\n\tsave() {\n\t\treturn this._format.toHexString( this.getValue(), this._rgbScale );\n\t}\n\n\tload( value ) {\n\t\tthis._setValueFromHexString( value );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.value = this._format.toHexString( this.getValue(), this._rgbScale );\n\t\tif ( !this._textFocused ) {\n\t\t\tthis.$text.value = this.$input.value.substring( 1 );\n\t\t}\n\t\tthis.$display.style.backgroundColor = this.$input.value;\n\t\treturn this;\n\t}\n\n}\n\nclass FunctionController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'lil-function' );\n\n\t\t// Buttons are the only case where widget contains name\n\t\tthis.$button = document.createElement( 'button' );\n\t\tthis.$button.appendChild( this.$name );\n\t\tthis.$widget.appendChild( this.$button );\n\n\t\tthis.$button.addEventListener( 'click', e => {\n\t\t\te.preventDefault();\n\t\t\tthis.getValue().call( this.object );\n\t\t\tthis._callOnChange();\n\t\t} );\n\n\t\t// enables :active pseudo class on mobile\n\t\tthis.$button.addEventListener( 'touchstart', () => {}, { passive: true } );\n\n\t\tthis.$disable = this.$button;\n\n\t}\n\n}\n\nclass NumberController extends Controller {\n\n\tconstructor( parent, object, property, min, max, step ) {\n\n\t\tsuper( parent, object, property, 'lil-number' );\n\n\t\tthis._initInput();\n\n\t\tthis.min( min );\n\t\tthis.max( max );\n\n\t\tconst stepExplicit = step !== undefined;\n\t\tthis.step( stepExplicit ? step : this._getImplicitStep(), stepExplicit );\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tdecimals( decimals ) {\n\t\tthis._decimals = decimals;\n\t\tthis.updateDisplay();\n\t\treturn this;\n\t}\n\n\tmin( min ) {\n\t\tthis._min = min;\n\t\tthis._onUpdateMinMax();\n\t\treturn this;\n\t}\n\n\tmax( max ) {\n\t\tthis._max = max;\n\t\tthis._onUpdateMinMax();\n\t\treturn this;\n\t}\n\n\tstep( step, explicit = true ) {\n\t\tthis._step = step;\n\t\tthis._stepExplicit = explicit;\n\t\treturn this;\n\t}\n\n\tupdateDisplay() {\n\n\t\tconst value = this.getValue();\n\n\t\tif ( this._hasSlider ) {\n\n\t\t\tlet percent = ( value - this._min ) / ( this._max - this._min );\n\t\t\tpercent = Math.max( 0, Math.min( percent, 1 ) );\n\n\t\t\tthis.$fill.style.width = percent * 100 + '%';\n\n\t\t}\n\n\t\tif ( !this._inputFocused ) {\n\t\t\tthis.$input.value = this._decimals === undefined ? value : value.toFixed( this._decimals );\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t_initInput() {\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'text' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\t// On touch devices only, use input[type=number] to force a numeric keyboard.\n\t\t// Ideally we could use one input type everywhere, but [type=number] has quirks\n\t\t// on desktop, and [inputmode=decimal] has quirks on iOS.\n\t\t// See https://github.com/georgealways/lil-gui/pull/16\n\n\t\tconst isTouch = window.matchMedia( '(pointer: coarse)' ).matches;\n\n\t\tif ( isTouch ) {\n\t\t\tthis.$input.setAttribute( 'type', 'number' );\n\t\t\tthis.$input.setAttribute( 'step', 'any' );\n\t\t}\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$disable = this.$input;\n\n\t\tconst onInput = () => {\n\n\t\t\tlet value = parseFloat( this.$input.value );\n\n\t\t\tif ( isNaN( value ) ) return;\n\n\t\t\tif ( this._stepExplicit ) {\n\t\t\t\tvalue = this._snap( value );\n\t\t\t}\n\n\t\t\tthis.setValue( this._clamp( value ) );\n\n\t\t};\n\n\t\t// Keys & mouse wheel\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst increment = delta => {\n\n\t\t\tconst value = parseFloat( this.$input.value );\n\n\t\t\tif ( isNaN( value ) ) return;\n\n\t\t\tthis._snapClampSetValue( value + delta );\n\n\t\t\t// Force the input to updateDisplay when it's focused\n\t\t\tthis.$input.value = this.getValue();\n\n\t\t};\n\n\t\tconst onKeyDown = e => {\n\t\t\t// Using `e.key` instead of `e.code` also catches NumpadEnter\n\t\t\tif ( e.key === 'Enter' ) {\n\t\t\t\tthis.$input.blur();\n\t\t\t}\n\t\t\tif ( e.code === 'ArrowUp' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._arrowKeyMultiplier( e ) );\n\t\t\t}\n\t\t\tif ( e.code === 'ArrowDown' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._arrowKeyMultiplier( e ) * -1 );\n\t\t\t}\n\t\t};\n\n\t\tconst onWheel = e => {\n\t\t\tif ( this._inputFocused ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._normalizeMouseWheel( e ) );\n\t\t\t}\n\t\t};\n\n\t\t// Vertical drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tlet testingForVerticalDrag = false,\n\t\t\tinitClientX,\n\t\t\tinitClientY,\n\t\t\tprevClientY,\n\t\t\tinitValue,\n\t\t\tdragDelta;\n\n\t\t// Once the mouse is dragged more than DRAG_THRESH px on any axis, we decide\n\t\t// on the user's intent: horizontal means highlight, vertical means drag.\n\t\tconst DRAG_THRESH = 5;\n\n\t\tconst onMouseDown = e => {\n\n\t\t\tinitClientX = e.clientX;\n\t\t\tinitClientY = prevClientY = e.clientY;\n\t\t\ttestingForVerticalDrag = true;\n\n\t\t\tinitValue = this.getValue();\n\t\t\tdragDelta = 0;\n\n\t\t\twindow.addEventListener( 'mousemove', onMouseMove );\n\t\t\twindow.addEventListener( 'mouseup', onMouseUp );\n\n\t\t};\n\n\t\tconst onMouseMove = e => {\n\n\t\t\tif ( testingForVerticalDrag ) {\n\n\t\t\t\tconst dx = e.clientX - initClientX;\n\t\t\t\tconst dy = e.clientY - initClientY;\n\n\t\t\t\tif ( Math.abs( dy ) > DRAG_THRESH ) {\n\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tthis.$input.blur();\n\t\t\t\t\ttestingForVerticalDrag = false;\n\t\t\t\t\tthis._setDraggingStyle( true, 'vertical' );\n\n\t\t\t\t} else if ( Math.abs( dx ) > DRAG_THRESH ) {\n\n\t\t\t\t\tonMouseUp();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// This isn't an else so that the first move counts towards dragDelta\n\t\t\tif ( !testingForVerticalDrag ) {\n\n\t\t\t\tconst dy = e.clientY - prevClientY;\n\n\t\t\t\tdragDelta -= dy * this._step * this._arrowKeyMultiplier( e );\n\n\t\t\t\t// Clamp dragDelta so we don't have 'dead space' after dragging past bounds.\n\t\t\t\t// We're okay with the fact that bounds can be undefined here.\n\t\t\t\tif ( initValue + dragDelta > this._max ) {\n\t\t\t\t\tdragDelta = this._max - initValue;\n\t\t\t\t} else if ( initValue + dragDelta < this._min ) {\n\t\t\t\t\tdragDelta = this._min - initValue;\n\t\t\t\t}\n\n\t\t\t\tthis._snapClampSetValue( initValue + dragDelta );\n\n\t\t\t}\n\n\t\t\tprevClientY = e.clientY;\n\n\t\t};\n\n\t\tconst onMouseUp = () => {\n\t\t\tthis._setDraggingStyle( false, 'vertical' );\n\t\t\tthis._callOnFinishChange();\n\t\t\twindow.removeEventListener( 'mousemove', onMouseMove );\n\t\t\twindow.removeEventListener( 'mouseup', onMouseUp );\n\t\t};\n\n\t\t// Focus state & onFinishChange\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst onFocus = () => {\n\t\t\tthis._inputFocused = true;\n\t\t};\n\n\t\tconst onBlur = () => {\n\t\t\tthis._inputFocused = false;\n\t\t\tthis.updateDisplay();\n\t\t\tthis._callOnFinishChange();\n\t\t};\n\n\t\tthis.$input.addEventListener( 'input', onInput );\n\t\tthis.$input.addEventListener( 'keydown', onKeyDown );\n\t\tthis.$input.addEventListener( 'wheel', onWheel, { passive: false } );\n\t\tthis.$input.addEventListener( 'mousedown', onMouseDown );\n\t\tthis.$input.addEventListener( 'focus', onFocus );\n\t\tthis.$input.addEventListener( 'blur', onBlur );\n\n\t}\n\n\t_initSlider() {\n\n\t\tthis._hasSlider = true;\n\n\t\t// Build DOM\n\t\t// ---------------------------------------------------------------------\n\n\t\tthis.$slider = document.createElement( 'div' );\n\t\tthis.$slider.classList.add( 'lil-slider' );\n\n\t\tthis.$fill = document.createElement( 'div' );\n\t\tthis.$fill.classList.add( 'lil-fill' );\n\n\t\tthis.$slider.appendChild( this.$fill );\n\t\tthis.$widget.insertBefore( this.$slider, this.$input );\n\n\t\tthis.domElement.classList.add( 'lil-has-slider' );\n\n\t\t// Map clientX to value\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst map = ( v, a, b, c, d ) => {\n\t\t\treturn ( v - a ) / ( b - a ) * ( d - c ) + c;\n\t\t};\n\n\t\tconst setValueFromX = clientX => {\n\t\t\tconst rect = this.$slider.getBoundingClientRect();\n\t\t\tlet value = map( clientX, rect.left, rect.right, this._min, this._max );\n\t\t\tthis._snapClampSetValue( value );\n\t\t};\n\n\t\t// Mouse drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst mouseDown = e => {\n\t\t\tthis._setDraggingStyle( true );\n\t\t\tsetValueFromX( e.clientX );\n\t\t\twindow.addEventListener( 'mousemove', mouseMove );\n\t\t\twindow.addEventListener( 'mouseup', mouseUp );\n\t\t};\n\n\t\tconst mouseMove = e => {\n\t\t\tsetValueFromX( e.clientX );\n\t\t};\n\n\t\tconst mouseUp = () => {\n\t\t\tthis._callOnFinishChange();\n\t\t\tthis._setDraggingStyle( false );\n\t\t\twindow.removeEventListener( 'mousemove', mouseMove );\n\t\t\twindow.removeEventListener( 'mouseup', mouseUp );\n\t\t};\n\n\t\t// Touch drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tlet testingForScroll = false, prevClientX, prevClientY;\n\n\t\tconst beginTouchDrag = e => {\n\t\t\te.preventDefault();\n\t\t\tthis._setDraggingStyle( true );\n\t\t\tsetValueFromX( e.touches[ 0 ].clientX );\n\t\t\ttestingForScroll = false;\n\t\t};\n\n\t\tconst onTouchStart = e => {\n\n\t\t\tif ( e.touches.length > 1 ) return;\n\n\t\t\t// If we're in a scrollable container, we should wait for the first\n\t\t\t// touchmove to see if the user is trying to slide or scroll.\n\t\t\tif ( this._hasScrollBar ) {\n\n\t\t\t\tprevClientX = e.touches[ 0 ].clientX;\n\t\t\t\tprevClientY = e.touches[ 0 ].clientY;\n\t\t\t\ttestingForScroll = true;\n\n\t\t\t} else {\n\n\t\t\t\t// Otherwise, we can set the value straight away on touchstart.\n\t\t\t\tbeginTouchDrag( e );\n\n\t\t\t}\n\n\t\t\twindow.addEventListener( 'touchmove', onTouchMove, { passive: false } );\n\t\t\twindow.addEventListener( 'touchend', onTouchEnd );\n\n\t\t};\n\n\t\tconst onTouchMove = e => {\n\n\t\t\tif ( testingForScroll ) {\n\n\t\t\t\tconst dx = e.touches[ 0 ].clientX - prevClientX;\n\t\t\t\tconst dy = e.touches[ 0 ].clientY - prevClientY;\n\n\t\t\t\tif ( Math.abs( dx ) > Math.abs( dy ) ) {\n\n\t\t\t\t\t// We moved horizontally, set the value and stop checking.\n\t\t\t\t\tbeginTouchDrag( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// This was, in fact, an attempt to scroll. Abort.\n\t\t\t\t\twindow.removeEventListener( 'touchmove', onTouchMove );\n\t\t\t\t\twindow.removeEventListener( 'touchend', onTouchEnd );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\te.preventDefault();\n\t\t\t\tsetValueFromX( e.touches[ 0 ].clientX );\n\n\t\t\t}\n\n\t\t};\n\n\t\tconst onTouchEnd = () => {\n\t\t\tthis._callOnFinishChange();\n\t\t\tthis._setDraggingStyle( false );\n\t\t\twindow.removeEventListener( 'touchmove', onTouchMove );\n\t\t\twindow.removeEventListener( 'touchend', onTouchEnd );\n\t\t};\n\n\t\t// Mouse wheel\n\t\t// ---------------------------------------------------------------------\n\n\t\t// We have to use a debounced function to call onFinishChange because\n\t\t// there's no way to tell when the user is \"done\" mouse-wheeling.\n\t\tconst callOnFinishChange = this._callOnFinishChange.bind( this );\n\t\tconst WHEEL_DEBOUNCE_TIME = 400;\n\t\tlet wheelFinishChangeTimeout;\n\n\t\tconst onWheel = e => {\n\n\t\t\t// ignore vertical wheels if there's a scrollbar\n\t\t\tconst isVertical = Math.abs( e.deltaX ) < Math.abs( e.deltaY );\n\t\t\tif ( isVertical && this._hasScrollBar ) return;\n\n\t\t\te.preventDefault();\n\n\t\t\t// set value\n\t\t\tconst delta = this._normalizeMouseWheel( e ) * this._step;\n\t\t\tthis._snapClampSetValue( this.getValue() + delta );\n\n\t\t\t// force the input to updateDisplay when it's focused\n\t\t\tthis.$input.value = this.getValue();\n\n\t\t\t// debounce onFinishChange\n\t\t\tclearTimeout( wheelFinishChangeTimeout );\n\t\t\twheelFinishChangeTimeout = setTimeout( callOnFinishChange, WHEEL_DEBOUNCE_TIME );\n\n\t\t};\n\n\t\tthis.$slider.addEventListener( 'mousedown', mouseDown );\n\t\tthis.$slider.addEventListener( 'touchstart', onTouchStart, { passive: false } );\n\t\tthis.$slider.addEventListener( 'wheel', onWheel, { passive: false } );\n\n\t}\n\n\t_setDraggingStyle( active, axis = 'horizontal' ) {\n\t\tif ( this.$slider ) {\n\t\t\tthis.$slider.classList.toggle( 'lil-active', active );\n\t\t}\n\t\tdocument.body.classList.toggle( 'lil-dragging', active );\n\t\tdocument.body.classList.toggle( `lil-${axis}`, active );\n\t}\n\n\t_getImplicitStep() {\n\n\t\tif ( this._hasMin && this._hasMax ) {\n\t\t\treturn ( this._max - this._min ) / 1000;\n\t\t}\n\n\t\treturn 0.1;\n\n\t}\n\n\t_onUpdateMinMax() {\n\n\t\tif ( !this._hasSlider && this._hasMin && this._hasMax ) {\n\n\t\t\t// If this is the first time we're hearing about min and max\n\t\t\t// and we haven't explicitly stated what our step is, let's\n\t\t\t// update that too.\n\t\t\tif ( !this._stepExplicit ) {\n\t\t\t\tthis.step( this._getImplicitStep(), false );\n\t\t\t}\n\n\t\t\tthis._initSlider();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t}\n\n\t_normalizeMouseWheel( e ) {\n\n\t\tlet { deltaX, deltaY } = e;\n\n\t\t// Safari and Chrome report weird non-integral values for a notched wheel,\n\t\t// but still expose actual lines scrolled via wheelDelta. Notched wheels\n\t\t// should behave the same way as arrow keys.\n\t\tif ( Math.floor( e.deltaY ) !== e.deltaY && e.wheelDelta ) {\n\t\t\tdeltaX = 0;\n\t\t\tdeltaY = -e.wheelDelta / 120;\n\t\t\tdeltaY *= this._stepExplicit ? 1 : 10;\n\t\t}\n\n\t\tconst wheel = deltaX + -deltaY;\n\n\t\treturn wheel;\n\n\t}\n\n\t_arrowKeyMultiplier( e ) {\n\n\t\tlet mult = this._stepExplicit ? 1 : 10;\n\n\t\tif ( e.shiftKey ) {\n\t\t\tmult *= 10;\n\t\t} else if ( e.altKey ) {\n\t\t\tmult /= 10;\n\t\t}\n\n\t\treturn mult;\n\n\t}\n\n\t_snap( value ) {\n\n\t\t// Make the steps \"start\" at min or max.\n\t\tlet offset = 0;\n\t\tif ( this._hasMin ) {\n\t\t\toffset = this._min;\n\t\t} else if ( this._hasMax ) {\n\t\t\toffset = this._max;\n\t\t}\n\n\t\tvalue -= offset;\n\n\t\tvalue = Math.round( value / this._step ) * this._step;\n\n\t\tvalue += offset;\n\n\t\t// Used to prevent \"flyaway\" decimals like 1.00000000000001\n\t\tvalue = parseFloat( value.toPrecision( 15 ) );\n\n\t\treturn value;\n\n\t}\n\n\t_clamp( value ) {\n\t\t// either condition is false if min or max is undefined\n\t\tif ( value < this._min ) value = this._min;\n\t\tif ( value > this._max ) value = this._max;\n\t\treturn value;\n\t}\n\n\t_snapClampSetValue( value ) {\n\t\tthis.setValue( this._clamp( this._snap( value ) ) );\n\t}\n\n\tget _hasScrollBar() {\n\t\tconst root = this.parent.root.$children;\n\t\treturn root.scrollHeight > root.clientHeight;\n\t}\n\n\tget _hasMin() {\n\t\treturn this._min !== undefined;\n\t}\n\n\tget _hasMax() {\n\t\treturn this._max !== undefined;\n\t}\n\n}\n\nclass OptionController extends Controller {\n\n\tconstructor( parent, object, property, options ) {\n\n\t\tsuper( parent, object, property, 'lil-option' );\n\n\t\tthis.$select = document.createElement( 'select' );\n\t\tthis.$select.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$display = document.createElement( 'div' );\n\t\tthis.$display.classList.add( 'lil-display' );\n\n\t\tthis.$select.addEventListener( 'change', () => {\n\t\t\tthis.setValue( this._values[ this.$select.selectedIndex ] );\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$select.addEventListener( 'focus', () => {\n\t\t\tthis.$display.classList.add( 'lil-focus' );\n\t\t} );\n\n\t\tthis.$select.addEventListener( 'blur', () => {\n\t\t\tthis.$display.classList.remove( 'lil-focus' );\n\t\t} );\n\n\t\tthis.$widget.appendChild( this.$select );\n\t\tthis.$widget.appendChild( this.$display );\n\n\t\tthis.$disable = this.$select;\n\n\t\tthis.options( options );\n\n\t}\n\n\toptions( options ) {\n\n\t\tthis._values = Array.isArray( options ) ? options : Object.values( options );\n\t\tthis._names = Array.isArray( options ) ? options : Object.keys( options );\n\n\t\tthis.$select.replaceChildren();\n\n\t\tthis._names.forEach( name => {\n\t\t\tconst $option = document.createElement( 'option' );\n\t\t\t$option.textContent = name;\n\t\t\tthis.$select.appendChild( $option );\n\t\t} );\n\n\t\tthis.updateDisplay();\n\n\t\treturn this;\n\n\t}\n\n\tupdateDisplay() {\n\t\tconst value = this.getValue();\n\t\tconst index = this._values.indexOf( value );\n\t\tthis.$select.selectedIndex = index;\n\t\tthis.$display.textContent = index === -1 ? value : this._names[ index ];\n\t\treturn this;\n\t}\n\n}\n\nclass StringController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'lil-string' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'text' );\n\t\tthis.$input.setAttribute( 'spellcheck', 'false' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$input.addEventListener( 'input', () => {\n\t\t\tthis.setValue( this.$input.value );\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'keydown', e => {\n\t\t\tif ( e.code === 'Enter' ) {\n\t\t\t\tthis.$input.blur();\n\t\t\t}\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'blur', () => {\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$disable = this.$input;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.value = this.getValue();\n\t\treturn this;\n\t}\n\n}\n\nvar stylesheet = `.lil-gui {\n font-family: var(--font-family);\n font-size: var(--font-size);\n line-height: 1;\n font-weight: normal;\n font-style: normal;\n text-align: left;\n color: var(--text-color);\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n --background-color: #1f1f1f;\n --text-color: #ebebeb;\n --title-background-color: #111111;\n --title-text-color: #ebebeb;\n --widget-color: #424242;\n --hover-color: #4f4f4f;\n --focus-color: #595959;\n --number-color: #2cc9ff;\n --string-color: #a2db3c;\n --font-size: 11px;\n --input-font-size: 11px;\n --font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Arial, sans-serif;\n --font-family-mono: Menlo, Monaco, Consolas, \"Droid Sans Mono\", monospace;\n --padding: 4px;\n --spacing: 4px;\n --widget-height: 20px;\n --title-height: calc(var(--widget-height) + var(--spacing) * 1.25);\n --name-width: 45%;\n --slider-knob-width: 2px;\n --slider-input-width: 27%;\n --color-input-width: 27%;\n --slider-input-min-width: 45px;\n --color-input-min-width: 45px;\n --folder-indent: 7px;\n --widget-padding: 0 0 0 3px;\n --widget-border-radius: 2px;\n --checkbox-size: calc(0.75 * var(--widget-height));\n --scrollbar-width: 5px;\n}\n.lil-gui, .lil-gui * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n.lil-gui.lil-root {\n width: var(--width, 245px);\n display: flex;\n flex-direction: column;\n background: var(--background-color);\n}\n.lil-gui.lil-root > .lil-title {\n background: var(--title-background-color);\n color: var(--title-text-color);\n}\n.lil-gui.lil-root > .lil-children {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.lil-gui.lil-root > .lil-children::-webkit-scrollbar {\n width: var(--scrollbar-width);\n height: var(--scrollbar-width);\n background: var(--background-color);\n}\n.lil-gui.lil-root > .lil-children::-webkit-scrollbar-thumb {\n border-radius: var(--scrollbar-width);\n background: var(--focus-color);\n}\n@media (pointer: coarse) {\n .lil-gui.lil-allow-touch-styles, .lil-gui.lil-allow-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n }\n}\n.lil-gui.lil-force-touch-styles, .lil-gui.lil-force-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n}\n.lil-gui.lil-auto-place, .lil-gui.autoPlace {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 1001;\n}\n\n.lil-controller {\n display: flex;\n align-items: center;\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n}\n.lil-controller.lil-disabled {\n opacity: 0.5;\n}\n.lil-controller.lil-disabled, .lil-controller.lil-disabled * {\n pointer-events: none !important;\n}\n.lil-controller > .lil-name {\n min-width: var(--name-width);\n flex-shrink: 0;\n white-space: pre;\n padding-right: var(--spacing);\n line-height: var(--widget-height);\n}\n.lil-controller .lil-widget {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-height: var(--widget-height);\n}\n.lil-controller.lil-string input {\n color: var(--string-color);\n}\n.lil-controller.lil-boolean {\n cursor: pointer;\n}\n.lil-controller.lil-color .lil-display {\n width: 100%;\n height: var(--widget-height);\n border-radius: var(--widget-border-radius);\n position: relative;\n}\n@media (hover: hover) {\n .lil-controller.lil-color .lil-display:hover:before {\n content: \" \";\n display: block;\n position: absolute;\n border-radius: var(--widget-border-radius);\n border: 1px solid #fff9;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n}\n.lil-controller.lil-color input[type=color] {\n opacity: 0;\n width: 100%;\n height: 100%;\n cursor: pointer;\n}\n.lil-controller.lil-color input[type=text] {\n margin-left: var(--spacing);\n font-family: var(--font-family-mono);\n min-width: var(--color-input-min-width);\n width: var(--color-input-width);\n flex-shrink: 0;\n}\n.lil-controller.lil-option select {\n opacity: 0;\n position: absolute;\n width: 100%;\n max-width: 100%;\n}\n.lil-controller.lil-option .lil-display {\n position: relative;\n pointer-events: none;\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n line-height: var(--widget-height);\n max-width: 100%;\n overflow: hidden;\n word-break: break-all;\n padding-left: 0.55em;\n padding-right: 1.75em;\n background: var(--widget-color);\n}\n@media (hover: hover) {\n .lil-controller.lil-option .lil-display.lil-focus {\n background: var(--focus-color);\n }\n}\n.lil-controller.lil-option .lil-display.lil-active {\n background: var(--focus-color);\n}\n.lil-controller.lil-option .lil-display:after {\n font-family: \"lil-gui\";\n content: \"↕\";\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n padding-right: 0.375em;\n}\n.lil-controller.lil-option .lil-widget,\n.lil-controller.lil-option select {\n cursor: pointer;\n}\n@media (hover: hover) {\n .lil-controller.lil-option .lil-widget:hover .lil-display {\n background: var(--hover-color);\n }\n}\n.lil-controller.lil-number input {\n color: var(--number-color);\n}\n.lil-controller.lil-number.lil-has-slider input {\n margin-left: var(--spacing);\n width: var(--slider-input-width);\n min-width: var(--slider-input-min-width);\n flex-shrink: 0;\n}\n.lil-controller.lil-number .lil-slider {\n width: 100%;\n height: var(--widget-height);\n background: var(--widget-color);\n border-radius: var(--widget-border-radius);\n padding-right: var(--slider-knob-width);\n overflow: hidden;\n cursor: ew-resize;\n touch-action: pan-y;\n}\n@media (hover: hover) {\n .lil-controller.lil-number .lil-slider:hover {\n background: var(--hover-color);\n }\n}\n.lil-controller.lil-number .lil-slider.lil-active {\n background: var(--focus-color);\n}\n.lil-controller.lil-number .lil-slider.lil-active .lil-fill {\n opacity: 0.95;\n}\n.lil-controller.lil-number .lil-fill {\n height: 100%;\n border-right: var(--slider-knob-width) solid var(--number-color);\n box-sizing: content-box;\n}\n\n.lil-dragging .lil-gui {\n --hover-color: var(--widget-color);\n}\n.lil-dragging * {\n cursor: ew-resize !important;\n}\n.lil-dragging.lil-vertical * {\n cursor: ns-resize !important;\n}\n\n.lil-gui .lil-title {\n height: var(--title-height);\n font-weight: 600;\n padding: 0 var(--padding);\n width: 100%;\n text-align: left;\n background: none;\n text-decoration-skip: objects;\n}\n.lil-gui .lil-title:before {\n font-family: \"lil-gui\";\n content: \"▾\";\n padding-right: 2px;\n display: inline-block;\n}\n.lil-gui .lil-title:active {\n background: var(--title-background-color);\n opacity: 0.75;\n}\n@media (hover: hover) {\n body:not(.lil-dragging) .lil-gui .lil-title:hover {\n background: var(--title-background-color);\n opacity: 0.85;\n }\n .lil-gui .lil-title:focus {\n text-decoration: underline var(--focus-color);\n }\n}\n.lil-gui.lil-root > .lil-title:focus {\n text-decoration: none !important;\n}\n.lil-gui.lil-closed > .lil-title:before {\n content: \"▸\";\n}\n.lil-gui.lil-closed > .lil-children {\n transform: translateY(-7px);\n opacity: 0;\n}\n.lil-gui.lil-closed:not(.lil-transition) > .lil-children {\n display: none;\n}\n.lil-gui.lil-transition > .lil-children {\n transition-duration: 300ms;\n transition-property: height, opacity, transform;\n transition-timing-function: cubic-bezier(0.2, 0.6, 0.35, 1);\n overflow: hidden;\n pointer-events: none;\n}\n.lil-gui .lil-children:empty:before {\n content: \"Empty\";\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n display: block;\n height: var(--widget-height);\n font-style: italic;\n line-height: var(--widget-height);\n opacity: 0.5;\n}\n.lil-gui.lil-root > .lil-children > .lil-gui > .lil-title {\n border: 0 solid var(--widget-color);\n border-width: 1px 0;\n transition: border-color 300ms;\n}\n.lil-gui.lil-root > .lil-children > .lil-gui.lil-closed > .lil-title {\n border-bottom-color: transparent;\n}\n.lil-gui + .lil-controller {\n border-top: 1px solid var(--widget-color);\n margin-top: 0;\n padding-top: var(--spacing);\n}\n.lil-gui .lil-gui .lil-gui > .lil-title {\n border: none;\n}\n.lil-gui .lil-gui .lil-gui > .lil-children {\n border: none;\n margin-left: var(--folder-indent);\n border-left: 2px solid var(--widget-color);\n}\n.lil-gui .lil-gui .lil-controller {\n border: none;\n}\n\n.lil-gui label, .lil-gui input, .lil-gui button {\n -webkit-tap-highlight-color: transparent;\n}\n.lil-gui input {\n border: 0;\n outline: none;\n font-family: var(--font-family);\n font-size: var(--input-font-size);\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n background: var(--widget-color);\n color: var(--text-color);\n width: 100%;\n}\n@media (hover: hover) {\n .lil-gui input:hover {\n background: var(--hover-color);\n }\n .lil-gui input:active {\n background: var(--focus-color);\n }\n}\n.lil-gui input:disabled {\n opacity: 1;\n}\n.lil-gui input[type=text],\n.lil-gui input[type=number] {\n padding: var(--widget-padding);\n -moz-appearance: textfield;\n}\n.lil-gui input[type=text]:focus,\n.lil-gui input[type=number]:focus {\n background: var(--focus-color);\n}\n.lil-gui input[type=checkbox] {\n appearance: none;\n width: var(--checkbox-size);\n height: var(--checkbox-size);\n border-radius: var(--widget-border-radius);\n text-align: center;\n cursor: pointer;\n}\n.lil-gui input[type=checkbox]:checked:before {\n font-family: \"lil-gui\";\n content: \"✓\";\n font-size: var(--checkbox-size);\n line-height: var(--checkbox-size);\n}\n@media (hover: hover) {\n .lil-gui input[type=checkbox]:focus {\n box-shadow: inset 0 0 0 1px var(--focus-color);\n }\n}\n.lil-gui button {\n outline: none;\n cursor: pointer;\n font-family: var(--font-family);\n font-size: var(--font-size);\n color: var(--text-color);\n width: 100%;\n border: none;\n}\n.lil-gui .lil-controller button {\n height: var(--widget-height);\n text-transform: none;\n background: var(--widget-color);\n border-radius: var(--widget-border-radius);\n}\n@media (hover: hover) {\n .lil-gui .lil-controller button:hover {\n background: var(--hover-color);\n }\n .lil-gui .lil-controller button:focus {\n box-shadow: inset 0 0 0 1px var(--focus-color);\n }\n}\n.lil-gui .lil-controller button:active {\n background: var(--focus-color);\n}\n\n@font-face {\n font-family: \"lil-gui\";\n src: url(\"data:application/font-woff2;charset=utf-8;base64,d09GMgABAAAAAALkAAsAAAAABtQAAAKVAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACDMgqBBIEbATYCJAMUCwwABCAFhAoHgQQbHAbIDiUFEYVARAAAYQTVWNmz9MxhEgodq49wYRUFKE8GWNiUBxI2LBRaVnc51U83Gmhs0Q7JXWMiz5eteLwrKwuxHO8VFxUX9UpZBs6pa5ABRwHA+t3UxUnH20EvVknRerzQgX6xC/GH6ZUvTcAjAv122dF28OTqCXrPuyaDER30YBA1xnkVutDDo4oCi71Ca7rrV9xS8dZHbPHefsuwIyCpmT7j+MnjAH5X3984UZoFFuJ0yiZ4XEJFxjagEBeqs+e1iyK8Xf/nOuwF+vVK0ur765+vf7txotUi0m3N0m/84RGSrBCNrh8Ee5GjODjF4gnWP+dJrH/Lk9k4oT6d+gr6g/wssA2j64JJGP6cmx554vUZnpZfn6ZfX2bMwPPrlANsB86/DiHjhl0OP+c87+gaJo/gY084s3HoYL/ZkWHTRfBXvvoHnnkHvngKun4KBE/ede7tvq3/vQOxDXB1/fdNz6XbPdcr0Vhpojj9dG+owuSKFsslCi1tgEjirjXdwMiov2EioadxmqTHUCIwo8NgQaeIasAi0fTYSPTbSmwbMOFduyh9wvBrESGY0MtgRjtgQR8Q1bRPohn2UoCRZf9wyYANMXFeJTysqAe0I4mrherOekFdKMrYvJjLvOIUM9SuwYB5DVZUwwVjJJOaUnZCmcEkIZZrKqNvRGRMvmFZsmhP4VMKCSXBhSqUBxgMS7h0cZvEd71AWkEhGWaeMFcNnpqyJkyXgYL7PQ1MoSq0wDAkRtJIijkZSmqYTiSImfLiSWXIZwhRh3Rug2X0kk1Dgj+Iu43u5p98ghopcpSo0Uyc8SnjlYX59WUeaMoDqmVD2TOWD9a4pCRAzf2ECgwGcrHjPOWY9bNxq/OL3I/QjwEAAAA=\") format(\"woff2\");\n}`;\n\nfunction _injectStyles( cssContent ) {\n\tconst injected = document.createElement( 'style' );\n\tinjected.innerHTML = cssContent;\n\tconst before = document.querySelector( 'head link[rel=stylesheet], head style' );\n\tif ( before ) {\n\t\tdocument.head.insertBefore( injected, before );\n\t} else {\n\t\tdocument.head.appendChild( injected );\n\t}\n}\n\n\nlet stylesInjected = false;\n\nclass GUI {\n\n\t/**\n\t * Creates a panel that holds controllers.\n\t * @example\n\t * new GUI();\n\t * new GUI( { container: document.getElementById( 'custom' ) } );\n\t *\n\t * @param {object} [options]\n\t * @param {boolean} [options.autoPlace=true]\n\t * Adds the GUI to `document.body` and fixes it to the top right of the page.\n\t *\n\t * @param {Node} [options.container]\n\t * Adds the GUI to this DOM element. Overrides `autoPlace`.\n\t *\n\t * @param {number} [options.width=245]\n\t * Width of the GUI in pixels, usually set when name labels become too long. Note that you can make\n\t * name labels wider in CSS with `.lil‑gui { ‑‑name‑width: 55% }`.\n\t *\n\t * @param {string} [options.title=Controls]\n\t * Name to display in the title bar.\n\t *\n\t * @param {boolean} [options.closeFolders=false]\n\t * Pass `true` to close all folders in this GUI by default.\n\t *\n\t * @param {boolean} [options.injectStyles=true]\n\t * Injects the default stylesheet into the page if this is the first GUI.\n\t * Pass `false` to use your own stylesheet.\n\t *\n\t * @param {number} [options.touchStyles=true]\n\t * Makes controllers larger on touch devices. Pass `false` to disable touch styles.\n\t *\n\t * @param {GUI} [options.parent]\n\t * Adds this GUI as a child in another GUI. Usually this is done for you by `addFolder()`.\n\t */\n\tconstructor( {\n\t\tparent,\n\t\tautoPlace = parent === undefined,\n\t\tcontainer,\n\t\twidth,\n\t\ttitle = 'Controls',\n\t\tcloseFolders = false,\n\t\tinjectStyles = true,\n\t\ttouchStyles = true\n\t} = {} ) {\n\n\t\t/**\n\t\t * The GUI containing this folder, or `undefined` if this is the root GUI.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * The top level GUI containing this folder, or `this` if this is the root GUI.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.root = parent ? parent.root : this;\n\n\t\t/**\n\t\t * The list of controllers and folders contained by this GUI.\n\t\t * @type {Array<GUI|Controller>}\n\t\t */\n\t\tthis.children = [];\n\n\t\t/**\n\t\t * The list of controllers contained by this GUI.\n\t\t * @type {Array<Controller>}\n\t\t */\n\t\tthis.controllers = [];\n\n\t\t/**\n\t\t * The list of folders contained by this GUI.\n\t\t * @type {Array<GUI>}\n\t\t */\n\t\tthis.folders = [];\n\n\t\t/**\n\t\t * Used to determine if the GUI is closed. Use `gui.open()` or `gui.close()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._closed = false;\n\n\t\t/**\n\t\t * Used to determine if the GUI is hidden. Use `gui.show()` or `gui.hide()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._hidden = false;\n\n\t\t/**\n\t\t * The outermost container element.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.domElement = document.createElement( 'div' );\n\t\tthis.domElement.classList.add( 'lil-gui' );\n\n\t\t/**\n\t\t * The DOM element that contains the title.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$title = document.createElement( 'button' );\n\t\tthis.$title.classList.add( 'lil-title' );\n\t\tthis.$title.setAttribute( 'aria-expanded', true );\n\n\t\tthis.$title.addEventListener( 'click', () => this.openAnimated( this._closed ) );\n\n\t\t// enables :active pseudo class on mobile\n\t\tthis.$title.addEventListener( 'touchstart', () => {}, { passive: true } );\n\n\t\t/**\n\t\t * The DOM element that contains children.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$children = document.createElement( 'div' );\n\t\tthis.$children.classList.add( 'lil-children' );\n\n\t\tthis.domElement.appendChild( this.$title );\n\t\tthis.domElement.appendChild( this.$children );\n\n\t\tthis.title( title );\n\n\t\tif ( this.parent ) {\n\n\t\t\tthis.parent.children.push( this );\n\t\t\tthis.parent.folders.push( this );\n\n\t\t\tthis.parent.$children.appendChild( this.domElement );\n\n\t\t\t// Stop the constructor early, everything onward only applies to root GUI's\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.domElement.classList.add( 'lil-root' );\n\n\t\tif ( touchStyles ) {\n\t\t\tthis.domElement.classList.add( 'lil-allow-touch-styles' );\n\t\t}\n\n\t\t// Inject stylesheet if we haven't done that yet\n\t\tif ( !stylesInjected && injectStyles ) {\n\t\t\t_injectStyles( stylesheet );\n\t\t\tstylesInjected = true;\n\t\t}\n\n\t\tif ( container ) {\n\n\t\t\tcontainer.appendChild( this.domElement );\n\n\t\t} else if ( autoPlace ) {\n\n\t\t\t// https://github.com/georgealways/lil-gui/pull/154\n\t\t\t// .autoPlace is deprecated in 0.21.0, but unlikely to conflict with user styles.\n\t\t\t// keeping it for backwards compatibility.\n\t\t\tthis.domElement.classList.add( 'lil-auto-place', 'autoPlace' );\n\t\t\tdocument.body.appendChild( this.domElement );\n\n\t\t}\n\n\t\tif ( width ) {\n\t\t\tthis.domElement.style.setProperty( '--width', width + 'px' );\n\t\t}\n\n\t\tthis._closeFolders = closeFolders;\n\n\t}\n\n\t/**\n\t * Adds a controller to the GUI, inferring controller type using the `typeof` operator.\n\t * @example\n\t * gui.add( object, 'property' );\n\t * gui.add( object, 'number', 0, 100, 1 );\n\t * gui.add( object, 'options', [ 1, 2, 3 ] );\n\t *\n\t * @param {object} object The object the controller will modify.\n\t * @param {string} property Name of the property to control.\n\t * @param {number|object|Array} [$1] Minimum value for number controllers, or the set of\n\t * selectable values for a dropdown.\n\t * @param {number} [max] Maximum value for number controllers.\n\t * @param {number} [step] Step value for number controllers.\n\t * @returns {Controller}\n\t */\n\tadd( object, property, $1, max, step ) {\n\n\t\tif ( Object( $1 ) === $1 ) {\n\n\t\t\treturn new OptionController( this, object, property, $1 );\n\n\t\t}\n\n\t\tconst initialValue = object[ property ];\n\n\t\tswitch ( typeof initialValue ) {\n\n\t\t\tcase 'number':\n\n\t\t\t\treturn new NumberController( this, object, property, $1, max, step );\n\n\t\t\tcase 'boolean':\n\n\t\t\t\treturn new BooleanController( this, object, property );\n\n\t\t\tcase 'string':\n\n\t\t\t\treturn new StringController( this, object, property );\n\n\t\t\tcase 'function':\n\n\t\t\t\treturn new FunctionController( this, object, property );\n\n\t\t}\n\n\t\tconsole.error( `gui.add failed\n\tproperty:`, property, `\n\tobject:`, object, `\n\tvalue:`, initialValue );\n\n\t}\n\n\t/**\n\t * Adds a color controller to the GUI.\n\t * @example\n\t * params = {\n\t * \tcssColor: '#ff00ff',\n\t * \trgbColor: { r: 0, g: 0.2, b: 0.4 },\n\t * \tcustomRange: [ 0, 127, 255 ],\n\t * };\n\t *\n\t * gui.addColor( params, 'cssColor' );\n\t * gui.addColor( params, 'rgbColor' );\n\t * gui.addColor( params, 'customRange', 255 );\n\t *\n\t * @param {object} object The object the controller will modify.\n\t * @param {string} property Name of the property to control.\n\t * @param {number} rgbScale Maximum value for a color channel when using an RGB color. You may\n\t * need to set this to 255 if your colors are too bright.\n\t * @returns {Controller}\n\t */\n\taddColor( object, property, rgbScale = 1 ) {\n\t\treturn new ColorController( this, object, property, rgbScale );\n\t}\n\n\t/**\n\t * Adds a folder to the GUI, which is just another GUI. This method returns\n\t * the nested GUI so you can add controllers to it.\n\t * @example\n\t * const folder = gui.addFolder( 'Position' );\n\t * folder.add( position, 'x' );\n\t * folder.add( position, 'y' );\n\t * folder.add( position, 'z' );\n\t *\n\t * @param {string} title Name to display in the folder's title bar.\n\t * @returns {GUI}\n\t */\n\taddFolder( title ) {\n\t\tconst folder = new GUI( { parent: this, title } );\n\t\tif ( this.root._closeFolders ) folder.close();\n\t\treturn folder;\n\t}\n\n\t/**\n\t * Recalls values that were saved with `gui.save()`.\n\t * @param {object} obj\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {this}\n\t */\n\tload( obj, recursive = true ) {\n\n\t\tif ( obj.controllers ) {\n\n\t\t\tthis.controllers.forEach( c => {\n\n\t\t\t\tif ( c instanceof FunctionController ) return;\n\n\t\t\t\tif ( c._name in obj.controllers ) {\n\t\t\t\t\tc.load( obj.controllers[ c._name ] );\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t\tif ( recursive && obj.folders ) {\n\n\t\t\tthis.folders.forEach( f => {\n\n\t\t\t\tif ( f._title in obj.folders ) {\n\t\t\t\t\tf.load( obj.folders[ f._title ] );\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Returns an object mapping controller names to values. The object can be passed to `gui.load()` to\n\t * recall these values.\n\t * @example\n\t * {\n\t * \tcontrollers: {\n\t * \t\tprop1: 1,\n\t * \t\tprop2: 'value',\n\t * \t\t...\n\t * \t},\n\t * \tfolders: {\n\t * \t\tfolderName1: { controllers, folders },\n\t * \t\tfolderName2: { controllers, folders }\n\t * \t\t...\n\t * \t}\n\t * }\n\t *\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {object}\n\t */\n\tsave( recursive = true ) {\n\n\t\tconst obj = {\n\t\t\tcontrollers: {},\n\t\t\tfolders: {}\n\t\t};\n\n\t\tthis.controllers.forEach( c => {\n\n\t\t\tif ( c instanceof FunctionController ) return;\n\n\t\t\tif ( c._name in obj.controllers ) {\n\t\t\t\tthrow new Error( `Cannot save GUI with duplicate property \"${c._name}\"` );\n\t\t\t}\n\n\t\t\tobj.controllers[ c._name ] = c.save();\n\n\t\t} );\n\n\t\tif ( recursive ) {\n\n\t\t\tthis.folders.forEach( f => {\n\n\t\t\t\tif ( f._title in obj.folders ) {\n\t\t\t\t\tthrow new Error( `Cannot save GUI with duplicate folder \"${f._title}\"` );\n\t\t\t\t}\n\n\t\t\t\tobj.folders[ f._title ] = f.save();\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn obj;\n\n\t}\n\n\t/**\n\t * Opens a GUI or folder. GUI and folders are open by default.\n\t * @param {boolean} open Pass false to close.\n\t * @returns {this}\n\t * @example\n\t * gui.open(); // open\n\t * gui.open( false ); // close\n\t * gui.open( gui._closed ); // toggle\n\t */\n\topen( open = true ) {\n\n\t\tthis._setClosed( !open );\n\n\t\tthis.$title.setAttribute( 'aria-expanded', !this._closed );\n\t\tthis.domElement.classList.toggle( 'lil-closed', this._closed );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Closes the GUI.\n\t * @returns {this}\n\t */\n\tclose() {\n\t\treturn this.open( false );\n\t}\n\n\t_setClosed( closed ) {\n\t\tif ( this._closed === closed ) return;\n\t\tthis._closed = closed;\n\t\tthis._callOnOpenClose( this );\n\t}\n\n\t/**\n\t * Shows the GUI after it's been hidden.\n\t * @param {boolean} show\n\t * @returns {this}\n\t * @example\n\t * gui.show();\n\t * gui.show( false ); // hide\n\t * gui.show( gui._hidden ); // toggle\n\t */\n\tshow( show = true ) {\n\n\t\tthis._hidden = !show;\n\n\t\tthis.domElement.style.display = this._hidden ? 'none' : '';\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Hides the GUI.\n\t * @returns {this}\n\t */\n\thide() {\n\t\treturn this.show( false );\n\t}\n\n\topenAnimated( open = true ) {\n\n\t\t// set state immediately\n\t\tthis._setClosed( !open );\n\n\t\tthis.$title.setAttribute( 'aria-expanded', !this._closed );\n\n\t\t// wait for next frame to measure $children\n\t\trequestAnimationFrame( () => {\n\n\t\t\t// explicitly set initial height for transition\n\t\t\tconst initialHeight = this.$children.clientHeight;\n\t\t\tthis.$children.style.height = initialHeight + 'px';\n\n\t\t\tthis.domElement.classList.add( 'lil-transition' );\n\n\t\t\tconst onTransitionEnd = e => {\n\t\t\t\tif ( e.target !== this.$children ) return;\n\t\t\t\tthis.$children.style.height = '';\n\t\t\t\tthis.domElement.classList.remove( 'lil-transition' );\n\t\t\t\tthis.$children.removeEventListener( 'transitionend', onTransitionEnd );\n\t\t\t};\n\n\t\t\tthis.$children.addEventListener( 'transitionend', onTransitionEnd );\n\n\t\t\t// todo: this is wrong if children's scrollHeight makes for a gui taller than maxHeight\n\t\t\tconst targetHeight = !open ? 0 : this.$children.scrollHeight;\n\n\t\t\tthis.domElement.classList.toggle( 'lil-closed', !open );\n\n\t\t\trequestAnimationFrame( () => {\n\t\t\t\tthis.$children.style.height = targetHeight + 'px';\n\t\t\t} );\n\n\t\t} );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Change the title of this GUI.\n\t * @param {string} title\n\t * @returns {this}\n\t */\n\ttitle( title ) {\n\t\t/**\n\t\t * Current title of the GUI. Use `gui.title( 'Title' )` to modify this value.\n\t\t * @type {string}\n\t\t */\n\t\tthis._title = title;\n\t\tthis.$title.textContent = title;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Resets all controllers to their initial values.\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {this}\n\t */\n\treset( recursive = true ) {\n\t\tconst controllers = recursive ? this.controllersRecursive() : this.controllers;\n\t\tcontrollers.forEach( c => c.reset() );\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pass a function to be called whenever a controller in this GUI changes.\n\t * @param {function({object:object, property:string, value:any, controller:Controller})} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onChange( event => {\n\t * \tevent.object // object that was modified\n\t * \tevent.property // string, name of property\n\t * \tevent.value // new value of controller\n\t * \tevent.controller // controller that was modified\n\t * } );\n\t */\n\tonChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onChange` events. Don't modify this value\n\t\t * directly. Use the `gui.onChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onChange = callback;\n\t\treturn this;\n\t}\n\n\t_callOnChange( controller ) {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnChange( controller );\n\t\t}\n\n\t\tif ( this._onChange !== undefined ) {\n\t\t\tthis._onChange.call( this, {\n\t\t\t\tobject: controller.object,\n\t\t\t\tproperty: controller.property,\n\t\t\t\tvalue: controller.getValue(),\n\t\t\t\tcontroller\n\t\t\t} );\n\t\t}\n\n\t}\n\n\t/**\n\t * Pass a function to be called whenever a controller in this GUI has finished changing.\n\t * @param {function({object:object, property:string, value:any, controller:Controller})} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onFinishChange( event => {\n\t * \tevent.object // object that was modified\n\t * \tevent.property // string, name of property\n\t * \tevent.value // new value of controller\n\t * \tevent.controller // controller that was modified\n\t * } );\n\t */\n\tonFinishChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onFinishChange` events. Don't modify this value\n\t\t * directly. Use the `gui.onFinishChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onFinishChange = callback;\n\t\treturn this;\n\t}\n\n\t_callOnFinishChange( controller ) {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnFinishChange( controller );\n\t\t}\n\n\t\tif ( this._onFinishChange !== undefined ) {\n\t\t\tthis._onFinishChange.call( this, {\n\t\t\t\tobject: controller.object,\n\t\t\t\tproperty: controller.property,\n\t\t\t\tvalue: controller.getValue(),\n\t\t\t\tcontroller\n\t\t\t} );\n\t\t}\n\n\t}\n\n\t/**\n\t * Pass a function to be called when this GUI or its descendants are opened or closed.\n\t * @param {function(GUI)} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onOpenClose( changedGUI => {\n\t * \tconsole.log( changedGUI._closed );\n\t * } );\n\t */\n\tonOpenClose( callback ) {\n\t\tthis._onOpenClose = callback;\n\t\treturn this;\n\t}\n\n\t_callOnOpenClose( changedGUI ) {\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnOpenClose( changedGUI );\n\t\t}\n\n\t\tif ( this._onOpenClose !== undefined ) {\n\t\t\tthis._onOpenClose.call( this, changedGUI );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys all DOM elements and event listeners associated with this GUI.\n\t */\n\tdestroy() {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent.children.splice( this.parent.children.indexOf( this ), 1 );\n\t\t\tthis.parent.folders.splice( this.parent.folders.indexOf( this ), 1 );\n\t\t}\n\n\t\tif ( this.domElement.parentElement ) {\n\t\t\tthis.domElement.parentElement.removeChild( this.domElement );\n\t\t}\n\n\t\tArray.from( this.children ).forEach( c => c.destroy() );\n\n\t}\n\n\t/**\n\t * Returns an array of controllers contained by this GUI and its descendents.\n\t * @returns {Controller[]}\n\t */\n\tcontrollersRecursive() {\n\t\tlet controllers = Array.from( this.controllers );\n\t\tthis.folders.forEach( f => {\n\t\t\tcontrollers = controllers.concat( f.controllersRecursive() );\n\t\t} );\n\t\treturn controllers;\n\t}\n\n\t/**\n\t * Returns an array of folders contained by this GUI and its descendents.\n\t * @returns {GUI[]}\n\t */\n\tfoldersRecursive() {\n\t\tlet folders = Array.from( this.folders );\n\t\tthis.folders.forEach( f => {\n\t\t\tfolders = folders.concat( f.foldersRecursive() );\n\t\t} );\n\t\treturn folders;\n\t}\n\n}\n\nexport { BooleanController, ColorController, Controller, FunctionController, GUI, NumberController, OptionController, StringController, GUI as default };\n","/**\n * Config Panel Manager\n * @module scene/static/ConfigPanelManager\n *\n * Manages the lifecycle of the lil-gui configuration panel for component editing.\n */\n\nimport GUI from 'lil-gui';\nimport type { UUID, Component } from 'simple-circuit-engine/core';\nimport type { IFactoryRegistry } from '../shared/components/ComponentVisualFactory';\nimport type { ConfigFormDefinition } from '../shared/types';\n\n/**\n * Manages lil-gui configuration panel for component config editing\n *\n * Responsibilities:\n * - Panel lifecycle (open, close, dispose)\n * - DOM container creation and positioning\n * - lil-gui initialization and form building\n * - Click-outside and Escape key handling\n * - onChange event wiring to update component config\n * - Event emission for config changes\n */\nexport class ConfigPanelManager {\n private factoryRegistry: IFactoryRegistry;\n private readonly editComponentConfig: (componentId: UUID, newConfig: Map<string, string>) => void;\n\n // Panel state\n private _isOpen: boolean = false;\n private _currentComponentId: UUID | null = null;\n private gui: GUI | null = null;\n private container: HTMLDivElement | null = null;\n private formDataObject: Record<string, any> = {};\n\n // Event handlers (stored for removal)\n private clickOutsideHandler: ((event: MouseEvent) => void) | null = null;\n private escapeHandler: ((event: KeyboardEvent) => void) | null = null;\n\n /**\n * Create a new ConfigPanelManager\n *\n * @param factoryRegistry - Factory registry for getting component factories\n * @param editComponentConfig - Function to edit component config\n * @param _camera - Three.js camera (reserved for future use)\n * @param _domElement - Container DOM element (reserved for future use)\n */\n constructor(\n factoryRegistry: IFactoryRegistry,\n editComponentConfig: (componentId: UUID, newConfig: Map<string, string>) => void,\n _camera: unknown,\n _domElement: unknown\n ) {\n this.factoryRegistry = factoryRegistry;\n this.editComponentConfig = editComponentConfig;\n }\n\n /**\n * Check if panel is currently open\n */\n get isOpen(): boolean {\n return this._isOpen;\n }\n\n /**\n * Get the ID of the component currently being edited\n */\n get currentComponentId(): UUID | null {\n return this._currentComponentId;\n }\n\n /**\n * Open the config panel for a component\n *\n * @param component - component to edit\n * @param screenPosition - Screen coordinates for panel positioning\n * @returns true if panel opened, false if component has no config\n */\n open(component: Component, screenPosition: { x: number; y: number }): boolean {\n // Close existing panel if open\n if (this._isOpen) {\n this.close();\n }\n\n const factory = this.factoryRegistry.get(component.type);\n const formDef = factory.getConfigFormDefinition();\n\n if (!formDef || formDef.fields.length === 0) {\n return false; // No configurable options\n }\n\n // Create container\n this.container = document.createElement('div');\n this.container.style.position = 'absolute';\n this.container.style.zIndex = '1000';\n document.body.appendChild(this.container);\n\n // Position container (will be implemented in T007)\n this.positionContainer(screenPosition);\n\n // Create lil-gui (will be implemented in T008)\n this.buildGui(formDef, component, factory);\n\n // Setup event listeners (will be implemented in T009, T010)\n this.setupEventListeners();\n\n this._isOpen = true;\n this._currentComponentId = component.id;\n\n return true;\n }\n\n /**\n * Close the config panel if open\n */\n close(): void {\n if (!this._isOpen) {\n return;\n }\n\n // Destroy lil-gui\n if (this.gui) {\n this.gui.destroy();\n this.gui = null;\n }\n\n // Remove container from DOM\n if (this.container) {\n document.body.removeChild(this.container);\n this.container = null;\n }\n\n // Remove event listeners\n this.removeEventListeners();\n\n this._isOpen = false;\n this._currentComponentId = null;\n this.formDataObject = {};\n }\n\n /**\n * Dispose of all resources\n */\n dispose(): void {\n this.close();\n }\n\n /**\n * Position the container adjacent to component (right side preferred)\n */\n private positionContainer(screenPosition: { x: number; y: number }): void {\n if (!this.container) return;\n\n const PANEL_WIDTH = 300; // Approximate lil-gui width\n const OFFSET_X = 20; // Spacing from component\n const VIEWPORT_PADDING = 10; // Min distance from viewport edge\n\n // Calculate preferred position (right side)\n let left = screenPosition.x + OFFSET_X;\n let top = screenPosition.y;\n\n // Check viewport overflow and adjust\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // If panel would overflow right edge, position to left of component\n if (left + PANEL_WIDTH > viewportWidth - VIEWPORT_PADDING) {\n left = screenPosition.x - PANEL_WIDTH - OFFSET_X;\n }\n\n // If still overflows left edge, clamp to viewport\n if (left < VIEWPORT_PADDING) {\n left = VIEWPORT_PADDING;\n }\n\n // Clamp top to viewport bounds\n if (top < VIEWPORT_PADDING) {\n top = VIEWPORT_PADDING;\n } else if (top > viewportHeight - VIEWPORT_PADDING) {\n top = viewportHeight - VIEWPORT_PADDING - 100; // Approximate panel height\n }\n\n this.container.style.left = `${left}px`;\n this.container.style.top = `${top}px`;\n }\n\n /**\n * Build lil-gui from form definition\n */\n private buildGui(formDef: ConfigFormDefinition, component: any, factory: any): void {\n if (!this.container) return;\n\n // Create lil-gui instance\n this.gui = new GUI({ container: this.container, width: 280 });\n this.gui.title(`Config: ${component.type}`);\n\n // Map core config to form data\n const formData = factory.mapCoreConfigToForm(component.config);\n\n // Convert Map to plain object for lil-gui\n this.formDataObject = {};\n for (const [key, value] of formData.entries()) {\n this.formDataObject[key] = value;\n }\n\n // Build controls for each field (T015: wire onChange handlers)\n for (const field of formDef.fields) {\n switch (field.type) {\n case 'boolean':\n this.gui\n .add(this.formDataObject, field.key)\n .name(field.label)\n .onChange(() => this.onValueChange(component, factory));\n break;\n\n case 'dropdown':\n if (field.options) {\n this.gui\n .add(this.formDataObject, field.key, field.options)\n .name(field.label)\n .onChange(() => this.onValueChange(component, factory));\n }\n break;\n\n case 'number':\n const controller = this.gui\n .add(this.formDataObject, field.key)\n .name(field.label)\n .onChange(() => this.onValueChange(component, factory));\n if (field.min !== undefined) controller.min(field.min);\n if (field.max !== undefined) controller.max(field.max);\n if (field.step !== undefined) controller.step(field.step);\n break;\n\n case 'text':\n this.gui\n .add(this.formDataObject, field.key)\n .name(field.label)\n .onChange(() => this.onValueChange(component, factory));\n break;\n\n case 'color':\n this.gui\n .addColor(this.formDataObject, field.key)\n .name(field.label)\n .onChange(() => this.onValueChange(component, factory));\n break;\n }\n }\n }\n\n /**\n * Handle value change in the config form (T016, T020, T021)\n * Maps form data back to core config and updates the component\n *\n * @param _component - Component being edited\n * @param factory - Visual factory for the component\n */\n private onValueChange(_component: any, factory: any): void {\n // Convert formDataObject back to Map for mapping\n const formDataMap = new Map<string, any>();\n for (const [key, value] of Object.entries(this.formDataObject)) {\n formDataMap.set(key, value);\n }\n // Map form data back to core config format\n const coreConfig = factory.mapFormToCoreConfig(formDataMap) as Map<string, string>;\n // call editComponentConfig to update the component\n if (this._currentComponentId) {\n this.editComponentConfig(this._currentComponentId, coreConfig);\n }\n }\n\n /**\n * Setup event listeners for dismissing the panel\n */\n private setupEventListeners(): void {\n // Click-outside detection\n this.clickOutsideHandler = (event: MouseEvent) => {\n if (!this.container) return;\n\n const target = event.target as Node;\n // Check if click is outside the panel container\n if (!this.container.contains(target)) {\n this.close();\n }\n };\n\n // Add with a small delay to avoid immediate closure from the click that opened it\n setTimeout(() => {\n if (this.clickOutsideHandler) {\n document.addEventListener('pointerdown', this.clickOutsideHandler);\n }\n }, 100);\n\n // Escape key handling\n this.escapeHandler = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n this.close();\n }\n };\n document.addEventListener('keydown', this.escapeHandler);\n }\n\n /**\n * Remove event listeners\n */\n private removeEventListeners(): void {\n if (this.clickOutsideHandler) {\n document.removeEventListener('pointerdown', this.clickOutsideHandler);\n this.clickOutsideHandler = null;\n }\n if (this.escapeHandler) {\n document.removeEventListener('keydown', this.escapeHandler);\n this.escapeHandler = null;\n }\n }\n}\n","/**\n * Static Circuit Controller for editing circuits\n * @module scene/static/CircuitController\n *\n * Manages static circuit THREE.js scene with support for editing tools.\n */\n\nimport * as THREE from 'three';\nimport type { Euler } from 'three';\nimport type { Component, Wire, ENode, UUID, ComponentType, ENodeSourceType, Circuit } from 'simple-circuit-engine/core';\nimport { ENodeType } from 'simple-circuit-engine/core';\nimport type { IFactoryRegistry } from '../shared/components/ComponentVisualFactory';\nimport type { ToolType, SelectionData, SharedResources, ControllerOptions, IEditingTool } from '../shared/types';\nimport { createGridHelper, gridToWorldPosition, gridToWorldRotation } from '../shared/utils/GeometryUtils';\nimport { BuildTool } from './tools/BuildTool';\nimport { AddComponentTool } from './tools/AddComponentTool';\nimport { MultiSelectTool } from './tools/MultiSelectTool';\nimport { SelectionManager } from '../shared/SelectionManager';\nimport { CircuitWriter } from './CircuitWriter';\nimport { AbstractCircuitController } from '../shared/AbstractCircuitController';\nimport { ConfigPanelManager } from './ConfigPanelManager';\nimport { controllerOptions } from '../shared/utils/Options';\n\n/**\n * Static Circuit Controller Implementation\n *\n * Manager providing a bidirectional interface between a Circuit and a Three.js scene/camera ready to be rendered.\n * Supports view manipulation and editing via integrated tool system.\n * Provides event hooks for error handling and state changes.\n */\nexport class CircuitController extends AbstractCircuitController {\n // flags\n private _editMode: boolean = false;\n // Circuit writer\n public readonly circuitWriter: CircuitWriter;\n // Selection manager\n private _selectionManager: SelectionManager | null = null;\n // Config panel manager\n private _configPanelManager: ConfigPanelManager | null = null;\n // Circuit RepositoryTool system\n private _tools: Map<ToolType, IEditingTool> = new Map();\n private _activeTool: ToolType | null = null;\n\n /**\n * Constructor and initialization\n */\n\n /**\n * Create a new Static Circuit Controller\n *\n * @param factoryRegistry - Component visual factory registry\n * @param sharedResources - Optional shared resources for facade pattern (CircuitEngine)\n * @throws {TypeError} factoryRegistry is null/undefined\n */\n constructor(factoryRegistry: IFactoryRegistry, sharedResources?: SharedResources) {\n super(factoryRegistry, sharedResources);\n\n this.circuitWriter = new CircuitWriter(this);\n\n this.handlePointerDown = this.handlePointerDown.bind(this);\n this.onContainerResize = this.onContainerResize.bind(this);\n }\n\n /**\n * Specific Initialization logic, performed after AbstractCircuitController initialization\n * @private\n */\n protected onInitialize(options?: ControllerOptions) {\n options = controllerOptions(options);\n // Initialize tools\n this._initializeTools();\n // Initialize Selection Manager\n this._initializeSelectionManager();\n // Initialize Config Panel Manager\n this._initializeConfigPanelManager();\n\n if (options.defaultTool) {\n this._initialized = true; // flag must be set before calling setActiveTool\n this.setEditMode(true);\n this.setActiveTool(options.defaultTool);\n }\n }\n\n protected emitReady() {\n this.emit('ready', { controllerType: 'static' });\n }\n\n /**\n * Enable or disable edit mode (FR-006, FR-027)\n * When disabled, deactivates any active tool and resets tool state\n *\n * @param enabled - True to enable edit mode, false to disable\n */\n setEditMode(enabled: boolean): void {\n this._checkInitialized();\n\n if (this._editMode === enabled) return; // No changge\n this._editMode = enabled;\n\n if (!enabled) {\n // Disable edit mode - deactivate active tool if any\n if (this._activeTool !== null) {\n const previousTool = this._activeTool;\n const tool = this._tools.get(previousTool);\n\n if (tool) {\n tool.onDeactivate();\n }\n this._activeTool = null;\n // Emit toolDeactivated event\n this.emit('toolDeactivated', { toolType: previousTool });\n }\n }\n }\n\n /**\n * specific disposal prepended at the beginning of dispose process\n */\n protected onDispose(): void {\n this.setEditMode(false); // Ensure edit mode and all tools are disabled\n\n // dispose ConfigPanelManager\n if (this._configPanelManager) {\n this._configPanelManager.dispose();\n this._configPanelManager = null;\n }\n // dispose SelectionManager\n if (this._selectionManager) {\n this._selectionManager.dispose();\n this._selectionManager = null;\n }\n // dispose own wireVisualManager\n this.wireVisualManager.dispose();\n }\n\n onSetActive(active: boolean): void {\n if (!active) {\n // Deactivate edit mode (which deactivates active tool and emits toolDeactivated)\n this.setEditMode(false);\n this._selectionManager?.deselect();\n } else {\n if (this._initialized && this._options && this._options.defaultTool) {\n this.setEditMode(true);\n this.setActiveTool(this._options.defaultTool);\n }\n }\n }\n\n setCircuit(circuit: Circuit | null): void {\n this._setCircuit(circuit);\n }\n\n /**\n * specific logic when to render a new set circuit\n * @protected\n */\n protected onSetCircuit() {\n this._fullUpdate();\n }\n\n /**\n * Get the SelectionManager instance for direct manipulation\n * @returns SelectionManager\n */\n getSelectionManager(): SelectionManager {\n this._checkInitialized();\n if (!this._selectionManager) {\n throw new Error('SelectionManager not initialized');\n }\n return this._selectionManager!;\n }\n\n private handlePointerDown(event: MouseEvent): void {\n // discard if right click or middle click\n if (event.button !== 0) {\n return;\n }\n\n // common behavior regardless of the tool: select on pointer down\n if (this._hoverManager?.getHoveredElement()) {\n // always: emit position event when hovered element\n const element = this._hoverManager.getHoveredElement()!;\n const alreadySelected = this._selectionManager!.isSelected(element.type, element.id);\n if (!alreadySelected) {\n this._selectionManager?.selectOne(element.type, element.id, element.object3D.userData);\n this.emit('select', this._selectionManager!.getSelection()!);\n }\n } else {\n // always: emit deselect event when not hovered element\n const hasSelection = this._selectionManager?.hasSelection();\n if (hasSelection) {\n const selection = this._selectionManager!.getSelection()!;\n this._selectionManager?.deselect();\n this.emit('deselect', selection);\n }\n }\n }\n\n private _applySelectionVisual(selection: SelectionData, selected: boolean): void {\n let components: Map<UUID, string | null> | null = null;\n let enodes: Map<UUID, string | null> | null = null;\n let wires: Map<UUID, string | null> | null = null;\n if (selection.kind === 'mono') {\n switch (selection.type) {\n case 'component':\n components = new Map<UUID, string | null>();\n components.set(selection.id, selection.data ?? null);\n break;\n case 'enode':\n enodes = new Map<UUID, string | null>();\n enodes.set(selection.id, selection.data ?? null);\n break;\n case 'wire':\n wires = new Map<UUID, string | null>();\n wires.set(selection.id, selection.data ?? null);\n break;\n default:\n break;\n }\n } else {\n components = selection.components || null;\n enodes = selection.enodes || null;\n wires = selection.wires || null;\n }\n\n if (components) {\n for (const [id, _data] of components) {\n const object3D = this._componentObject3Ds.get(id);\n if (!object3D) {\n continue;\n }\n try {\n const componentType = object3D.userData.componentType as ComponentType;\n const factory = this.factoryRegistry.get(componentType);\n if (selected) {\n factory.applySelection(object3D);\n } else {\n factory.removeSelection(object3D);\n }\n } catch (error) {\n console.warn(\n `Failed to ${selected ? 'apply' : 'remove'} component selection visual:`,\n error\n );\n }\n }\n }\n if (enodes) {\n for (const [id, _data] of enodes) {\n const object3D = this._enodeObject3Ds.get(id);\n if (!object3D) {\n continue;\n }\n if (!!object3D.userData.componentId) continue; // pins cannot be selected individually\n if (selected) {\n this.branchingPointVisualFactory.applySelection(object3D);\n } else {\n this.branchingPointVisualFactory.removeSelection(object3D);\n }\n }\n }\n if (wires) {\n for (const [id, _data] of wires) {\n if (selected) {\n this.wireVisualManager.applySelectedVisual(id);\n } else {\n this.wireVisualManager.removeSelectedVisual(id);\n }\n }\n }\n }\n\n private _initializeSelectionManager(): void {\n if (!this._scene || !this._camera || !this._container) {\n throw new Error('Scene, camera, and container must be initialized before SelectionManager');\n }\n\n // Create SelectionManager instance\n this._selectionManager = new SelectionManager();\n\n // Register callback to handle selection visual changes (T025)\n this._selectionManager.onSelectionChange((newSelection, previousSelection) => {\n // Remove selection visual from previous selection\n if (previousSelection) {\n this._applySelectionVisual(previousSelection, false);\n }\n // Apply selection visual to new selection\n if (newSelection) {\n this._applySelectionVisual(newSelection, true);\n }\n\n // Emit selectionChange event (T026)\n this.emit('selectionChange', {\n newSelection: previousSelection,\n previousSelection: newSelection,\n });\n });\n\n this._container.addEventListener('pointerdown', this.handlePointerDown);\n }\n\n /**\n * Initialize ConfigPanelManager (T013)\n * @private\n */\n private _initializeConfigPanelManager(): void {\n if (!this._scene || !this._camera || !this._container) {\n throw new Error('Scene, camera and container must be initialized before ConfigPanelManager');\n }\n\n // Create ConfigPanelManager instance\n this._configPanelManager = new ConfigPanelManager(\n this.factoryRegistry,\n this.editComponentConfig.bind(this),\n this._camera,\n this._container\n );\n }\n\n /**\n * Open the config panel for a component (T014)\n *\n * @param componentId - UUID of the component to edit\n * @param screenPosition - Screen coordinates for panel positioning\n * @returns true if panel opened, false if component has no config\n */\n openConfigPanel(componentId: UUID, screenPosition: { x: number; y: number }): boolean {\n this._checkInitialized();\n if (!this._configPanelManager) {\n throw new Error('ConfigPanelManager not initialized');\n }\n if (!this._circuit) {\n return false;\n }\n const component = this._circuit.getComponent(componentId);\n if (!component) {\n console.warn(`ConfigPanelManager.open: Component ${componentId} not found`);\n return false;\n }\n return this._configPanelManager.open(component, screenPosition);\n }\n\n /**\n * Tool System Methods\n */\n\n /**\n * Convenience method that toggle a tool on if it is off (possibly deactivating previous tool), or off if it is on\n * @param toolType\n */\n toggleTool(toolType: ToolType): void {\n const previousTool = this._activeTool;\n\n if (previousTool !== null) {\n this.deactivateTool(toolType);\n }\n if (previousTool === toolType) {\n return;\n }\n this.setActiveTool(toolType);\n }\n\n deactivateTool(toolType: ToolType): void {\n if (this._activeTool === null) {\n return;\n }\n if (this._activeTool !== toolType) {\n return; // only deactivate if the specified tool is active\n }\n\n const previousTool = this._activeTool;\n const tool = this._tools.get(previousTool);\n\n if (tool) {\n tool.onDeactivate();\n }\n\n this._activeTool = null;\n // Emit toolDeactivated event\n this.emit('toolDeactivated', { toolType: previousTool });\n }\n\n /**\n * Get the list of available component types for the AddComponent tool\n */\n getAvailableComponentTypes(): ComponentType[] {\n return this.factoryRegistry.getRegisteredTypes();\n }\n\n /**\n * Set the component type for the AddComponent tool\n * @param componentType\n */\n setAddComponentType(componentType: ComponentType | null): void {\n if (!this._editMode || this._activeTool !== 'addComponent') {\n throw new Error(\n 'Edit mode must be enabled and AddComponent tool must be active to set component type'\n );\n }\n const tool = this._tools.get('addComponent') as AddComponentTool;\n if (!tool) {\n throw new Error('AddComponent tool not found');\n }\n tool.setComponentType(componentType);\n }\n\n /**\n * Get the currently active tool (FR-028)\n *\n * @returns Current tool type or null if no tool is active\n */\n getActiveTool(): ToolType | null {\n return this._activeTool;\n }\n\n /**\n * Set the active editing tool (FR-026, FR-028, FR-034)\n * Only one tool can be active at a time\n * Switching tools will deactivate the previous tool\n *\n * @param toolType - Type of tool to activate\n * @throws {Error} If edit mode is not enabled\n */\n setActiveTool(toolType: ToolType): void {\n this._checkInitialized();\n\n if (!this._editMode) {\n throw new Error('Edit mode must be enabled to activate tools');\n }\n // Check if tool is already active\n if (this._activeTool === toolType) {\n return;\n } else if (this._activeTool !== null) {\n // Deactivate previous tool\n this.deactivateTool(this._activeTool);\n }\n\n // Activate new tool\n this._activeTool = toolType;\n const tool = this._tools.get(toolType);\n\n if (tool) {\n tool.onActivate();\n\n // Emit toolActivated event\n this.emit('toolActivated', { toolType });\n\n // Emit cursorChangeRequested event\n const cursorType = tool.getCursorType();\n this.emit('cursorChangeRequested', { cursorType });\n }\n }\n\n /**\n * Initialize editing tools\n * @private\n */\n private _initializeTools(): void {\n // Create tool instances\n this._tools.set('build', new BuildTool(this));\n this._tools.set('addComponent', new AddComponentTool(this));\n this._tools.set('multiSelect', new MultiSelectTool(this));\n }\n\n /**\n * recreate all visuals based on circuit data\n * Should be called on an already cleared scene\n * @private\n */\n private _fullUpdate(): void {\n this._checkInitialized();\n\n if (!this._circuit) return;\n\n // Create visuals for all circuit elements\n const components = this._circuit.getAllComponents();\n const wires = this._circuit.getAllWires();\n const enodes = this._circuit.getAllENodes();\n\n for (const component of components) {\n this._createComponentObject3D(component);\n }\n for (const enode of enodes) {\n this._createEnodeObject3D(enode);\n }\n for (const wire of wires) {\n this._createWireObject3D(wire);\n }\n }\n\n private _createComponentObject3D(component: Component): void {\n try {\n const factory = this.factoryRegistry.get(component.type);\n // Support both function-based (legacy) and class-based (new) factories\n const mesh = factory.createVisual(component);\n\n // Position mesh at component location (2D circuit -> 3D world)\n mesh.position.copy(gridToWorldPosition(component.position));\n mesh.rotation.copy(gridToWorldRotation(component.rotation));\n\n // Store component metadata\n mesh.userData.componentId = component.id;\n mesh.userData.componentType = component.type;\n\n this._scene!.add(mesh);\n this._indexComponentObject3D(component.id, mesh);\n\n // For edited pin enodes, update source type visual (component visual factory creates them only in their default mode)\n for (const pinId of component.pins) {\n const enode = this._circuit!.getENode(pinId);\n if (!enode || !enode.source) continue;\n const pinGroup = this._enodeObject3Ds.get(enode.id);\n if (!pinGroup) continue;\n this.factoryRegistry.getFallbackFactory().updatePinSourceType(pinGroup, enode.source);\n }\n } catch (error) {\n const err = error as Error;\n console.warn(`Failed to create mesh for component ${component.id}:`, err.message);\n this.emit('error', { message: `Component rendering failed: ${err.message}`, error: err });\n }\n }\n\n /**\n * Index component mesh and its pins meshes for interaction (hover, selection)\n * @param componentId\n * @param object3D\n * @private\n */\n private _indexComponentObject3D(componentId: string, object3D: THREE.Object3D): void {\n this._componentObject3Ds.set(componentId, object3D);\n object3D.traverse((obj) => {\n if (obj.userData && obj.userData.type === 'enodeGroup') {\n const enodeId = obj.userData.enodeId;\n if (enodeId) {\n this._enodeObject3Ds.set(enodeId, obj as THREE.Group);\n }\n }\n });\n }\n\n private _removeComponentObject3D(id: string): void {\n const group = this._componentObject3Ds.get(id);\n if (!group) {\n return;\n }\n\n this._scene!.remove(group);\n // Parcours complet pour disposer toutes les géométries / matériaux des enfants\n group.traverse((obj) => {\n if (obj.userData && obj.userData.type === 'enodeGroup') {\n this._removeEnodeObject3D(obj.userData.enodeId);\n } else if (obj instanceof THREE.Mesh) {\n if (obj.geometry) {\n obj.geometry.dispose();\n }\n if (obj.material) {\n if (Array.isArray(obj.material)) {\n obj.material.forEach((mat) => mat.dispose());\n } else {\n obj.material.dispose();\n }\n }\n }\n });\n this._componentObject3Ds.delete(id);\n }\n\n /**\n * Create enode (branching point ONLY) visual object and add to scene\n * pin enodes are created and attache to their components by createComponentObject3D()\n *\n * @param enode\n * @private\n */\n private _createEnodeObject3D(enode: ENode): void {\n // Skip pin enodes - they're visualized as part of their components\n if (enode.type === ENodeType.Pin) return;\n\n // Use BranchingPointVisualFactory to create the visual\n const group = this.branchingPointVisualFactory.createVisual(enode);\n\n // Use getPosition() to properly handle position retrieval\n group.position.copy(gridToWorldPosition(enode.getPosition(this._circuit!)));\n\n this._scene!.add(group);\n this._enodeObject3Ds.set(enode.id, group);\n }\n\n private _removeEnodeObject3D(id: string): void {\n const group = this._enodeObject3Ds.get(id);\n if (!group) return;\n group?.traverse((obj) => {\n if (obj instanceof THREE.Mesh) {\n if (obj.geometry) {\n obj.geometry.dispose();\n }\n if (obj.material) {\n if (Array.isArray(obj.material)) {\n obj.material.forEach((mat) => mat.dispose());\n } else {\n obj.material.dispose();\n }\n }\n }\n });\n this._scene!.remove(group);\n this._enodeObject3Ds.delete(id);\n }\n\n addBranchingPoint(worldPosition: THREE.Vector3, sourceType?: ENodeSourceType | undefined): ENode {\n const branchingPoint = this.circuitWriter.saveAddBranchingPoint(worldPosition, sourceType);\n // Create and add bp visual to scene\n this._createEnodeObject3D(branchingPoint);\n return branchingPoint;\n }\n\n /**\n * Split wire either :\n * - at a position, inserting a new branching point and two new wires replacing the deleted ones\n * - at an existing target enode, replacing the wire by two new wires connected to this enode\n * @param wireId\n * @param worldPosition - world Position for the new branching point : no effect if targetEnodeId provided\n * @param targetEnodeId - if provided, the existing enode to split the wire at\n */\n splitWire(\n wireId: UUID,\n worldPosition: THREE.Vector3,\n targetEnodeId: UUID | null = null\n ): { branchingPoint: ENode; wires: Wire[] } {\n // 1: Call CircuitWriter to split the wire and create branching point\n const result = this.circuitWriter.saveSplitWire(wireId, worldPosition, targetEnodeId);\n // 2: Remove old wire visual from scene\n this.wireVisualManager.removeWire(wireId);\n // 3: add new Branching point visual to the scene (only if not targetEnodeId)\n if (!targetEnodeId) {\n this._createEnodeObject3D(result.branchingPoint);\n }\n\n // 4: Add new wire visuals to scene\n for (const wire of result.wires) {\n this.wireVisualManager.createOrUpdateWire(wire);\n }\n\n return result;\n }\n\n /**\n * Remove branching point enode visual and update the circuit and visuals\n * @param enodeId\n */\n removeBranchingPoint(enodeId: UUID) {\n const result = this.circuitWriter.saveDeleteBranchingPoint(enodeId);\n if (!result) return;\n this._removeEnodeObject3D(enodeId);\n this._enodeObject3Ds.delete(enodeId);\n if (result.deletedWires) {\n for (const wireId of result.deletedWires) {\n this._removeWireObject3D(wireId);\n }\n }\n if (result.mergedWires) {\n for (const wireId of result.mergedWires) {\n this._removeWireObject3D(wireId);\n }\n }\n if (result.newWire) {\n this._createWireObject3D(result.newWire);\n }\n }\n\n private _createWireObject3D(wire: Wire): void {\n if (!this._scene || !this._circuit) {\n console.warn(`Cannot create wire ${wire.id}: scene or circuit not initialized`);\n return;\n }\n try {\n // Use WireVisualManager to create wire with pin-accurate endpoints\n this.wireVisualManager.createOrUpdateWire(wire);\n } catch (error) {\n const err = error as Error;\n console.warn(`Failed to create Line2 for wire ${wire.id}:`, err.message);\n }\n }\n\n /**\n * add a wire between two enodes : update the circuit and add visuals\n * @param sourceEnodeId\n * @param targetEnodeId\n */\n addWire(sourceEnodeId: UUID, targetEnodeId: UUID): Wire {\n const wire = this.circuitWriter.saveAddWire(sourceEnodeId, targetEnodeId);\n this.wireVisualManager.createOrUpdateWire(wire);\n return wire;\n }\n\n /**\n * Add a component to the circuit and scene\n *\n * @param type - Component type to add\n * @param worldPosition - Position in 3D world coordinates (x, z)\n * @param rotation - 3D world rotation\n * @param config - Optional configuration map for the component\n * @param pinSources - Optional array of source types for the component pins\n * @returns The created Component\n */\n addComponent(\n type: ComponentType,\n worldPosition: THREE.Vector3,\n rotation: Euler,\n config?: Map<string, string> | undefined,\n pinSources?: Array<ENodeSourceType | undefined | null> | undefined\n ): Component {\n // Create component in circuit model\n const component = this.circuitWriter.saveAddComponent(\n type,\n worldPosition,\n rotation,\n config,\n pinSources\n );\n // Create and add visual to scene\n this._createComponentObject3D(component);\n return component;\n }\n\n /**\n * edit component config and update visuals if necessary\n *\n * @param componentId\n * @param newConfig - map of parameters to be merged into the current config\n */\n editComponentConfig(componentId: UUID, newConfig: Map<string, string>) {\n const component = this.circuitWriter.saveEditComponentConfig(componentId, newConfig);\n if (!component) return;\n\n const object3D = this._componentObject3Ds.get(componentId);\n if (!object3D) return;\n // Update visuals if component hasChanged\n const factory = this.factoryRegistry.get(component.type);\n factory.updateFromConfiguration(object3D, component.config);\n // if config change, update wires connected to component\n // TODO optimize to do it only if necessary (size, ...)\n this.wireVisualManager.updateWiresForComponent(component.id);\n return;\n }\n\n /**\n * cycle component config and update visuals if necessary\n * have effect only on components that supports fast config cycle (used to invert logic or initial state of switches)\n * else use editComponentConfig\n *\n * @returns if the component has changed config\n * @param componentId\n */\n cycleComponentConfig(componentId: UUID): boolean {\n const result = this.circuitWriter.cycleComponentConfig(componentId);\n if (!result.hasChanged) {\n return false;\n }\n const object3D = this._componentObject3Ds.get(componentId);\n if (!object3D) return false;\n // Update visuals if component hasChanged\n const factory = this.factoryRegistry.get(result.component.type);\n factory.updateFromConfiguration(object3D, result.component.config);\n return true;\n }\n\n /**\n * Remove a component from the circuit and scene\n *\n * @param componentId - UUID of the component to remove\n */\n removeComponent(componentId: UUID): void {\n // Remove from circuit model (also removes connected wires)\n const result = this.circuitWriter.saveDeleteComponent(componentId);\n // Remove visuals for wires that were connected to the component\n for (const wireId of result.deletedWires) {\n this._removeWireObject3D(wireId);\n }\n // Remove component visual\n this._removeComponentObject3D(componentId);\n }\n\n /**\n * Update an enode based to a new source type.\n * @param enodeId - UUID of the enode\n * @param sourceType - New source type (null for no source)\n */\n updateEnodeSourceType(enodeId: UUID, sourceType: ENodeSourceType | null): void {\n const object3D = this._enodeObject3Ds.get(enodeId);\n if (!object3D) return;\n if (object3D.userData.lockedSourceType) return; // do not update locked source types\n\n this.circuitWriter.saveEditENodeSourceType(enodeId, sourceType);\n\n if (object3D.userData.componentId) {\n this.factoryRegistry.getFallbackFactory().updatePinSourceType(object3D, sourceType ?? null);\n } else {\n this.branchingPointVisualFactory.updateSourceType(object3D, sourceType ?? null);\n }\n }\n\n /**\n * Remove wire visual and update the circuit\n * @param wireId\n */\n removeWire(wireId: UUID) {\n this.circuitWriter.saveDeleteWire(wireId);\n this._removeWireObject3D(wireId);\n }\n\n /**\n * Automatically adjust the circuit grid size and divisions based on positions of all core circuit elements.\n */\n autoAdjustCircuitGridSize() {\n this._checkInitialized();\n if (!this._circuit) return;\n if (this.circuitWriter.saveAutoAdjustCircuitSize()) {\n // Update halfSize\n this._gridHalfSize = Math.ceil(this._circuit.metadata.size / 2);\n // Update grid helper\n if (this.grid) {\n this._scene!.remove(this.grid);\n this.grid.geometry.dispose();\n }\n const options = this._options || controllerOptions();\n this.grid = createGridHelper(\n this._circuit.metadata.size,\n this._circuit.metadata.divisions,\n options.colorCenterLine!,\n options.colorGrid!\n );\n this._scene!.add(this.grid);\n }\n }\n\n /**\n * Hook called before exporting the circuit visualization.\n * Saves world informations such as camera position, in the circuit metadata.\n */\n public beforeExport(): void {\n if (!this._circuit || !this._camera || !this._mapControls) return;\n try {\n this.circuitWriter.saveCameraOptions();\n } catch (error) {\n console.warn(error);\n }\n }\n\n private _removeWireObject3D(id: string): void {\n if (this._wireObject3Ds.has(id)) {\n // Use WireVisualManager to remove wire (handles all disposal and delete from map)\n this.wireVisualManager.removeWire(id);\n }\n }\n\n protected _removeAllVisuals(): void {\n // Remove all wire meshes\n for (const id of Array.from(this._wireObject3Ds.keys())) {\n this._removeWireObject3D(id);\n }\n // Remove all enode meshes\n for (const id of Array.from(this._enodeObject3Ds.keys())) {\n this._removeEnodeObject3D(id);\n }\n // Remove all component meshes\n for (const id of Array.from(this._componentObject3Ds.keys())) {\n this._removeComponentObject3D(id);\n }\n // remove grid\n if (this.grid) {\n this._scene!.remove(this.grid);\n this.grid.dispose();\n this._grid = null;\n }\n }\n}\n","/**\n * Simulation Circuit Controller\n * @module scene/simulation/CircuitRunnercontroller\n *\n * Controls live circuit simulation with real-time state updates and animated current flow.\n * Provides smooth interpolation between discrete simulation ticks for fluid animation.\n */\n\nimport * as THREE from 'three';\nimport type { Component, Wire, ENode, UserCommand, Circuit } from 'simple-circuit-engine/core';\nimport { ENodeType, ComponentType, CircuitRunner, BehaviorRegistry, SIMULATION_SPEED, TRANSITION_DEFAULTS } from 'simple-circuit-engine/core';\nimport type { IFactoryRegistry } from '../shared/components/ComponentVisualFactory';\nimport type { SharedResources, HoveredElement } from '../shared/types';\nimport { AbstractCircuitController } from '../shared/AbstractCircuitController';\nimport { gridToWorldPosition, gridToWorldRotation } from '../shared/utils/GeometryUtils';\n\n/**\n * Simulation Circuit Runner Controller Implementation\n *\n * Manages Three.js scene for live circuit simulation visualization.\n * Provides smooth interpolation between simulation ticks for 60fps rendering.\n * Animates current flow through wires and component state changes.\n */\nexport class CircuitRunnerController extends AbstractCircuitController {\n private _runner: CircuitRunner | null = null;\n private _behaviorRegistry: BehaviorRegistry;\n\n // Playback control state\n private _isPlaying: boolean = false;\n private _tickIntervalMs: number = SIMULATION_SPEED.DEFAULT_INTERVAL_MS;\n private _simulationLoopId: number | null = null;\n private _clickHandler: ((event: MouseEvent) => void) | null = null;\n\n /**\n * Create a new Simulation Circuit Controller\n *\n * @param factoryRegistry - Component visual factory registry\n * @param behaviorRegistry - Component behavior registry\n * @param sharedResources - Optional shared resources for facade pattern (CircuitEngine)\n * @throws {TypeError} If factoryRegistry is null/undefined\n */\n constructor(\n factoryRegistry: IFactoryRegistry,\n behaviorRegistry: BehaviorRegistry,\n sharedResources?: SharedResources\n ) {\n super(factoryRegistry, sharedResources);\n if (!behaviorRegistry) {\n throw new TypeError('BehaviorRegistry is required');\n }\n this._behaviorRegistry = behaviorRegistry;\n }\n\n /**\n * Check if simulation is currently playing (auto-advancing ticks)\n * Returns false if paused or no circuit loaded\n */\n get isPlaying(): boolean {\n return this._isPlaying;\n }\n\n /**\n * Get current tick interval in milliseconds\n * Default is 500ms (2 ticks per second)\n */\n get tickInterval(): number {\n return this._tickIntervalMs;\n }\n\n /**\n * Set tick interval in milliseconds (50-2000ms)\n * If simulation is playing, restarts the interval with new value\n *\n * @param value - Interval in milliseconds, must be between 50-2000ms\n * @throws {RangeError} If value is outside valid range\n */\n set tickInterval(value: number) {\n if (value < 50 || value > 2000) {\n throw new RangeError('Tick interval must be between 50 and 2000ms');\n }\n this._tickIntervalMs = value;\n\n // If playing, restart interval with new value\n if (this._isPlaying) {\n this.pause();\n this.play();\n }\n }\n\n /**\n * Get current simulation speed in ticks per second.\n * Range: 1-20 TPS\n */\n get simulationSpeed(): number {\n return Math.round(1000 / this._tickIntervalMs);\n }\n\n /**\n * Set simulation speed in ticks per second.\n * Value is clamped to range 1-20 TPS.\n * If simulation is playing, restarts the interval with new value.\n * Emits 'simulationSpeedChanged' event when speed changes.\n *\n * @param tps - Ticks per second (1-20)\n */\n set simulationSpeed(tps: number) {\n const previousSpeed = this.simulationSpeed;\n const clampedTps = Math.max(SIMULATION_SPEED.MIN_TPS, Math.min(SIMULATION_SPEED.MAX_TPS, tps));\n\n // Skip if no change\n if (clampedTps === previousSpeed) {\n return;\n }\n\n // Convert TPS to interval and apply\n this._tickIntervalMs = Math.round(1000 / clampedTps);\n\n // If playing, restart interval with new value\n if (this._isPlaying) {\n this.pause();\n this.play();\n }\n\n // Emit speed changed event\n this.emit('simulationSpeedChanged', {\n previousSpeed,\n newSpeed: clampedTps,\n });\n }\n\n /**\n * Minimum allowed simulation speed in ticks per second.\n */\n get minSimulationSpeed(): number {\n return SIMULATION_SPEED.MIN_TPS;\n }\n\n /**\n * Maximum allowed simulation speed in ticks per second.\n */\n get maxSimulationSpeed(): number {\n return SIMULATION_SPEED.MAX_TPS;\n }\n\n /**\n * Compute the number of ticks required for a transition given its duration in milliseconds.\n * Formula: ceil(transitionUserSpanMs × simulationSpeed / 1000), minimum 1.\n *\n * @param transitionUserSpanMs - Transition duration in milliseconds\n * @returns Number of ticks for the transition (minimum 1)\n */\n computeTickCount(transitionUserSpanMs: number): number {\n const tickCount = Math.ceil((transitionUserSpanMs * this.simulationSpeed) / 1000);\n return Math.max(1, tickCount);\n }\n\n /**\n * Get the transition duration from component config for user-driven transitions.\n * @param config - Component config map\n * @returns Transition duration in milliseconds (defaults to TRANSITION_USER_SPAN_MS)\n */\n private _getTransitionUserSpan(config: Map<string, string>): number {\n const value = parseInt(config.get('transitionUserSpan') || '', 10);\n if (isNaN(value) || value < 0) {\n return TRANSITION_DEFAULTS.TRANSITION_USER_SPAN_MS;\n }\n return value;\n }\n\n /**\n * Get current simulation tick number\n * Returns 0 if no circuit runner is loaded\n */\n get currentTick(): number {\n return this._runner?.getCurrentTick() ?? 0;\n }\n\n /**\n * Specific Initialization logic, performed after AbstractCircuitController initialization\n * @private\n */\n protected onInitialize() {\n // Register click handler for component interaction\n //this._pointerDownHandler = this._handlePointerDown.bind(this);\n //this._container!.addEventListener('pointerdown', this._pointerDownHandler);\n\n this._clickHandler = this._handleClick.bind(this);\n this._container!.addEventListener('click', this._clickHandler);\n }\n\n protected emitReady() {\n this.emit('ready', { controllerType: 'simulation' });\n }\n\n /**\n * specific disposal prepended at the beginning of dispose process\n */\n protected onDispose(): void {\n // Stop simulation loop if running\n if (this._isPlaying) {\n this.pause();\n }\n\n // Remove click event listener if registered\n if (this._clickHandler && this._container) {\n this._container.removeEventListener('click', this._clickHandler);\n this._clickHandler = null;\n }\n\n // Clear runner reference\n this._runner = null;\n }\n\n onSetActive(active: boolean): void {\n if (!active) {\n this.stop();\n this._runner = null;\n this._removeSimulationStateVisuals();\n } else {\n if (!this._circuit) return;\n // recreate runner for the current circuit (which can have been modified in edit mode while this controller was inactive)\n this._runner = new CircuitRunner(this._circuit, this._behaviorRegistry);\n this._fullUpdate();\n // no specific logic on activate\n }\n }\n\n setCircuit(circuit: Circuit | null): void {\n this._checkInitialized();\n if (circuit === this._circuit) return;\n\n // Stop current simulation if playing\n if (this._isPlaying) {\n this.stop();\n }\n this._runner = null;\n\n // When using shared resources, skip visual management (edit controller handles it)\n // Just update circuit reference and create runner\n if (this._useSharedResources) {\n this._circuit = circuit;\n this.wireVisualManager.setCircuit(circuit);\n if (circuit) {\n this._gridHalfSize = Math.ceil(circuit.metadata.size / 2);\n this._runner = new CircuitRunner(circuit, this._behaviorRegistry);\n }\n return;\n }\n\n // Standalone mode: full visual management\n this._setCircuit(circuit);\n }\n\n /**\n * specific logic when to render a new set circuit\n * @protected\n */\n protected onSetCircuit() {\n if (!this._circuit) return;\n this._runner = new CircuitRunner(this._circuit, this._behaviorRegistry);\n if (!this._useSharedResources) {\n // if standalone mode, activate immediately\n this.setActive(true);\n }\n }\n\n /**\n * Play automatic simulation playback\n * Simulation will advance at the configured tick interval until paused\n *\n * Requires a circuit runner to be loaded via setCircuitRunner()\n * Emits 'simulationPlayed' event on play\n * Emits 'simulationTick' event on each tick\n */\n play(): void {\n if (!this._runner) {\n console.warn('Cannot play: no circuit runner loaded');\n return;\n }\n\n if (this._isPlaying) {\n return; // Already playing\n }\n this._isPlaying = true;\n this.emit('simulationPlayed', { tick: this._runner.getCurrentTick() });\n\n // Start interval loop\n this._simulationLoopId = window.setInterval(() => {\n this._executeTick();\n }, this._tickIntervalMs);\n }\n\n /**\n * Pause automatic simulation playback\n * Safe to call even if already paused or no circuit loaded\n *\n * Emits 'simulationPaused' event\n */\n pause(): void {\n if (!this._isPlaying) {\n return; // Already paused\n }\n\n this._isPlaying = false;\n\n // Clear interval\n if (this._simulationLoopId !== null) {\n window.clearInterval(this._simulationLoopId);\n this._simulationLoopId = null;\n }\n\n this.emit('simulationPaused', { tick: this._runner?.getCurrentTick() ?? 0 });\n }\n\n /**\n * Execute a single simulation tick\n * Simulation remains paused after step, useful for debugging\n *\n * If currently playing, pauses first then steps\n * Requires a circuit runner to be loaded via setCircuitRunner()\n * Emits 'simulationStepped' event with tick result\n */\n step(): void {\n if (!this._runner) {\n console.warn('Cannot step: no circuit runner loaded');\n return;\n }\n\n // If playing, pause first\n if (this._isPlaying) {\n this.pause();\n }\n\n // Execute one tick\n const result = this._executeTick();\n\n this.emit('simulationStepped', { tick: this._runner.getCurrentTick(), result });\n }\n\n /**\n * Stop the simulation, reset visual to initial state\n * Simulation remains paused after step, useful for debugging\n *\n * If currently playing, pauses first then steps\n * Requires a circuit runner to be loaded via setCircuitRunner()\n * Emits 'simulationStopped' event with tick result (0)\n */\n stop(): void {\n if (!this._runner) {\n console.warn('Cannot step: no circuit runner loaded');\n return;\n }\n // If playing, pause first\n if (this._isPlaying) {\n this.pause();\n }\n this._runner.reset();\n // Update visuals to initial state\n this._visualUpdateFromSimulationState();\n const result = this._runner.getCurrentTick();\n\n this.emit('simulationStopped', { tick: result });\n }\n\n /**\n * Execute one simulation tick and update visuals\n * @private\n */\n private _executeTick(): unknown {\n if (!this._runner) {\n return null;\n }\n\n // Execute simulation tick\n const result = this._runner.tick();\n\n // Get dirty elements for optimized updates\n const dirty = this._runner.dirtyTracker.getDirtyElements();\n\n // Emit tick event\n this.emit('simulationTick', { tick: this._runner.getCurrentTick(), dirty });\n\n // Update visuals for changed elements\n this._updateDirtyComponents(dirty);\n this._updateDirtyWires(dirty);\n this._updateDirtyEnodes(dirty);\n\n return result;\n }\n\n /**\n * Update component animations for dirty components\n * @private\n */\n private _updateDirtyComponents(dirty: { components: ReadonlySet<string> }): void {\n if (!this._runner) return;\n\n // Update each dirty component's visual animation\n for (const componentId of dirty.components) {\n const object3D = this._componentObject3Ds.get(componentId);\n if (!object3D) continue;\n\n // Get component and its current state\n const component = this._circuit?.getComponent(componentId);\n if (!component) continue;\n\n const state = this._runner.getComponentState(componentId);\n if (!state) continue;\n\n // Get factory and update animation\n const factory = this.factoryRegistry.get(component.type);\n factory.updateAnimation(object3D, state);\n }\n }\n\n /**\n * Update wire visual state based on electrical state\n * @private\n */\n private _updateDirtyWires(dirty: { wires: ReadonlySet<string> }): void {\n if (!this._runner) return;\n\n // Update each dirty wire's material state\n for (const wireId of dirty.wires) {\n // Get wire electrical state from runner\n const wireState = this._runner.getWireState(wireId);\n if (!wireState) continue;\n\n // Determine material state based on electrical state\n // either idle, voltage, current or vc (voltage and current)\n let materialState: 'current' | 'voltage' | 'vc' | 'idle';\n if (wireState.hasCurrent && wireState.hasVoltage) {\n materialState = 'vc';\n } else if (wireState.hasVoltage) {\n materialState = 'voltage';\n } else if (wireState.hasCurrent) {\n materialState = 'current';\n } else {\n materialState = 'idle';\n }\n\n // Apply material state via WireVisualManager\n this.wireVisualManager.applyElectricalState(wireId, materialState);\n }\n }\n\n /**\n * Update enode visual state based on electrical state\n * Applies emissive glow to pins and branching points\n * @private\n */\n private _updateDirtyEnodes(dirty: { enodes: ReadonlySet<string> }): void {\n if (!this._runner) return;\n\n // Update each dirty enode's emissive state\n for (const enodeId of dirty.enodes) {\n // Get enode electrical state from runner\n const enodeState = this._runner.getEnodeState(enodeId);\n if (!enodeState) continue;\n\n // Get enode visual object (could be pin group or branching point)\n const enodeObject = this._enodeObject3Ds.get(enodeId);\n if (!enodeObject) continue;\n\n enodeObject.userData;\n\n // Determine emissive color based on electrical state\n // Priority: current (blue) > voltage (red) > none\n let emissiveColor: number;\n if (enodeState.hasCurrent && enodeState.hasVoltage) {\n enodeObject.userData.electricalState = 'vc';\n emissiveColor = 0xcc00cc; // Magenta for voltage and current (current circulating)\n } else if (enodeState.hasCurrent) {\n enodeObject.userData.electricalState = 'current';\n emissiveColor = 0x0000ff; // Blue for current\n } else if (enodeState.hasVoltage) {\n enodeObject.userData.electricalState = 'voltage';\n emissiveColor = 0xff0000; // Red for voltage only\n } else {\n enodeObject.userData.electricalState = 'idle';\n }\n\n // Apply emissive color to all meshes in the enode group\n enodeObject.traverse((obj) => {\n if (obj instanceof THREE.Mesh && obj.material) {\n const material = obj.material as THREE.MeshStandardMaterial;\n if (material.emissive) {\n material.emissive.setHex(emissiveColor);\n material.emissiveIntensity = emissiveColor === 0x000000 ? 0 : 1;\n }\n }\n });\n }\n }\n\n /**\n * rollback wires/enodes/components visuals to edition state (no simulation state)\n */\n _removeSimulationStateVisuals(): void {\n for (const wireId of this._wireObject3Ds.keys()) {\n this.wireVisualManager.applyElectricalState(wireId, 'idle');\n }\n for (const enodeId of this._enodeObject3Ds.keys()) {\n const enodeObject = this._enodeObject3Ds.get(enodeId);\n if (!enodeObject) continue;\n enodeObject.userData.electricalState = 'idle';\n enodeObject.traverse((obj) => {\n if (obj instanceof THREE.Mesh && obj.material) {\n const material = obj.material as THREE.MeshStandardMaterial;\n if (material.emissive) {\n material.emissive.setHex(0x000000);\n material.emissiveIntensity = 0;\n }\n }\n });\n }\n for (const componentId of this._componentObject3Ds.keys()) {\n const componentObject = this._componentObject3Ds.get(componentId);\n if (!componentObject) continue;\n // Get component and its current state\n const component = this._circuit?.getComponent(componentId);\n if (!component) continue;\n const factory = this.factoryRegistry.get(component.type);\n factory.updateAnimation(componentObject, null);\n }\n }\n\n /**\n * Handle click events for component interaction\n * @param event\n * @private\n */\n private _handleClick(event: MouseEvent): void {\n if (!this._active) return;\n // Only handle left clicks\n if (event.button !== 0) return;\n const hoveredElement = this.getHoveredElement();\n if (!hoveredElement) return;\n if (event.metaKey && event.ctrlKey) {\n this._handleCtrlClick(hoveredElement);\n } else {\n this._handleRegularClick(hoveredElement);\n }\n }\n\n /**\n * Handle regular click events : emit user commands to the runner\n * @param clickedElement\n * @private\n */\n private _handleRegularClick(clickedElement: HoveredElement) {\n if (!this._runner) return; // only process if we have a runner\n if (clickedElement.type === 'wire') return;\n let componentGroup = null;\n if (clickedElement.type === 'component') {\n componentGroup = clickedElement.object3D.parent;\n } else if (clickedElement.type === 'enode') {\n // for pin enodes, get parent component\n const enode = this._circuit?.getENode(clickedElement.id);\n if (!enode) return;\n if (!enode.component) return;\n componentGroup = this._componentObject3Ds.get(enode.component);\n }\n if (!componentGroup) return;\n const componentType = componentGroup.userData.componentType;\n const componentId = componentGroup.userData.componentId;\n switch (componentType) {\n case ComponentType.Switch: {\n // Get component to read its config\n const component = this._circuit?.getComponent(componentId);\n if (!component) return;\n\n // Compute tickCount from transitionUserSpan and simulationSpeed\n const transitionUserSpan = this._getTransitionUserSpan(component.config);\n const tickCount = this.computeTickCount(transitionUserSpan);\n\n const command: UserCommand = {\n type: 'toggle_switch',\n targetId: componentId,\n scheduledAtTick: this._runner.getCurrentTick(),\n parameters: new Map<string, string>([['tickCount', String(tickCount)]]),\n };\n // Submit command to runner and emit event\n this._runner.submitCommand(command);\n this.emit('simulationUserCommand', command);\n return;\n }\n default:\n return;\n }\n }\n\n private _handleCtrlClick(_clickedElement: HoveredElement) {\n // TODO: implement ctrl+click handling\n console.warn('TODO: implement ctrl+click handling');\n }\n\n /**\n * recreate all visuals based on circuit data\n * Should be called on an already cleared scene\n *\n * When using shared resources (CircuitEngine facade), skips visual creation\n * if visuals already exist in the shared maps (created by edit controller).\n * @private\n */\n private _fullUpdate(): void {\n this._checkInitialized();\n\n if (!this._circuit) return;\n\n // When using shared resources and visuals already exist, skip creation\n // The edit controller has already created all visuals\n\n if (!this._useSharedResources) {\n // Create visuals for all circuit elements\n const components = this._circuit.getAllComponents();\n const wires = this._circuit.getAllWires();\n const enodes = this._circuit.getAllENodes();\n\n for (const component of components) {\n this._createComponentObject3D(component);\n }\n for (const enode of enodes) {\n this._createEnodeObject3D(enode);\n }\n for (const wire of wires) {\n this._createWireObject3D(wire);\n }\n }\n\n // Always update simulation visual state (colors, animations) from simulation state\n this._visualUpdateFromSimulationState();\n }\n\n /**\n * Consider all elements as dirty to update all visual state according to simulation state\n * @private\n */\n private _visualUpdateFromSimulationState(): void {\n if (!this._circuit || !this._runner) return;\n\n const components = this._circuit.getAllComponents();\n const wires = this._circuit.getAllWires();\n const enodes = this._circuit.getAllENodes();\n\n this._updateDirtyComponents({ components: new Set(components.map((c) => c.id)) });\n this._updateDirtyEnodes({ enodes: new Set(enodes.map((e) => e.id)) });\n this._updateDirtyWires({ wires: new Set(wires.map((w) => w.id)) });\n }\n\n private _createComponentObject3D(component: Component): void {\n try {\n const factory = this.factoryRegistry.get(component.type);\n // Support both function-based (legacy) and class-based (new) factories\n const mesh = factory.createVisual(component);\n\n // Position mesh at component location (2D circuit -> 3D world)\n mesh.position.copy(gridToWorldPosition(component.position));\n mesh.rotation.copy(gridToWorldRotation(component.rotation));\n\n // Store component metadata\n mesh.userData.componentId = component.id;\n mesh.userData.componentType = component.type;\n\n this._scene!.add(mesh);\n this._indexComponentObject3D(component.id, mesh);\n\n // For edited pin enodes, update source type visual (component visual factory creates them only in their default mode)\n for (const pinId of component.pins) {\n const enode = this._circuit!.getENode(pinId);\n if (!enode || !enode.source) continue;\n const pinGroup = this._enodeObject3Ds.get(enode.id);\n if (!pinGroup) continue;\n this.factoryRegistry.getFallbackFactory().updatePinSourceType(pinGroup, enode.source);\n }\n } catch (error) {\n const err = error as Error;\n console.warn(`Failed to create mesh for component ${component.id}:`, err.message);\n this.emit('error', { message: `Component rendering failed: ${err.message}`, error: err });\n }\n }\n\n /**\n * Index component mesh and its pins meshes for interaction (hover, selection)\n * @param componentId\n * @param object3D\n * @private\n */\n private _indexComponentObject3D(componentId: string, object3D: THREE.Object3D): void {\n this._componentObject3Ds.set(componentId, object3D);\n object3D.traverse((obj) => {\n if (obj.userData && obj.userData.type === 'enodeGroup') {\n const enodeId = obj.userData.enodeId;\n if (enodeId) {\n this._enodeObject3Ds.set(enodeId, obj as THREE.Group);\n }\n }\n });\n }\n\n /**\n * Create enode (branching point ONLY) visual object and add to scene\n * pin enodes are created and attache to their components by createComponentObject3D()\n *\n * @param enode\n * @private\n */\n private _createEnodeObject3D(enode: ENode): void {\n // Skip pin enodes - they're visualized as part of their components\n if (enode.type === ENodeType.Pin) return;\n\n // Use BranchingPointVisualFactory to create the visual\n const group = this.branchingPointVisualFactory.createVisual(enode);\n\n // Use getPosition() to properly handle position retrieval\n group.position.copy(gridToWorldPosition(enode.getPosition(this._circuit!)));\n\n this._scene!.add(group);\n this._enodeObject3Ds.set(enode.id, group);\n }\n\n private _createWireObject3D(wire: Wire): void {\n if (!this._scene || !this._circuit) {\n console.warn(`Cannot create wire ${wire.id}: scene or circuit not initialized`);\n return;\n }\n try {\n // Use WireVisualManager to create wire with pin-accurate endpoints\n this.wireVisualManager.createOrUpdateWire(wire);\n } catch (error) {\n const err = error as Error;\n console.warn(`Failed to create Line2 for wire ${wire.id}:`, err.message);\n }\n }\n\n private _removeComponentObject3D(id: string): void {\n const group = this._componentObject3Ds.get(id);\n if (!group) {\n return;\n }\n\n // TODO : see if there are specific disposals to do (animations ?)\n\n this._scene!.remove(group);\n // Parcours complet pour disposer toutes les géométries / matériaux des enfants\n group.traverse((obj) => {\n if (obj.userData && obj.userData.type === 'enodeGroup') {\n this._removeEnodeObject3D(obj.userData.enodeId);\n } else if (obj instanceof THREE.Mesh) {\n if (obj.geometry) {\n obj.geometry.dispose();\n }\n if (obj.material) {\n if (Array.isArray(obj.material)) {\n obj.material.forEach((mat) => mat.dispose());\n } else {\n obj.material.dispose();\n }\n }\n }\n });\n this._componentObject3Ds.delete(id);\n }\n\n private _removeEnodeObject3D(id: string): void {\n const group = this._enodeObject3Ds.get(id);\n if (!group) return;\n\n // TODO : see if there are specific disposals to do (animations ?)\n\n group?.traverse((obj) => {\n if (obj instanceof THREE.Mesh) {\n if (obj.geometry) {\n obj.geometry.dispose();\n }\n if (obj.material) {\n if (Array.isArray(obj.material)) {\n obj.material.forEach((mat) => mat.dispose());\n } else {\n obj.material.dispose();\n }\n }\n }\n });\n this._scene!.remove(group);\n this._enodeObject3Ds.delete(id);\n }\n\n private _removeWireObject3D(id: string): void {\n if (this._wireObject3Ds.has(id)) {\n // TODO : see if there are specific disposals to do (animations ?)\n // Use WireVisualManager to remove wire (handles all disposal and delete from map)\n this.wireVisualManager.removeWire(id);\n }\n }\n\n protected _removeAllVisuals(): void {\n // TODO : see if there are specific disposals to do (animations ?)\n // Remove all wire meshes\n for (const id of Array.from(this._wireObject3Ds.keys())) {\n this._removeWireObject3D(id);\n }\n // Remove all enode meshes\n for (const id of Array.from(this._enodeObject3Ds.keys())) {\n this._removeEnodeObject3D(id);\n }\n // Remove all component meshes\n for (const id of Array.from(this._componentObject3Ds.keys())) {\n this._removeComponentObject3D(id);\n }\n }\n}\n","/**\n * CircuitEngine - Unified Facade for Circuit Editing and Simulation\n * @module scene/CircuitEngine\n *\n * Provides a unified API for both static circuit editing and live simulation,\n * managing mode transitions and resource sharing between controllers.\n */\n\nimport * as THREE from 'three';\nimport { MapControls } from 'three/addons/controls/MapControls.js';\nimport type { Line2 } from 'three/examples/jsm/lines/Line2.js';\nimport { EventEmitter } from './shared/EventEmitter';\n\nimport type { Circuit, BehaviorRegistry, UUID } from 'simple-circuit-engine/core';\n\nimport { CircuitController } from './static/CircuitController';\nimport { CircuitRunnerController } from './simulation/CircuitRunnerController';\nimport { HoverManager } from './shared/HoverManager';\nimport { WireVisualManager } from './shared/WireVisualManager';\nimport { BranchingPointVisualFactory } from './shared/BranchingPointVisualFactory';\nimport { createPerspectiveCamera, updateCamera } from './shared/utils/CameraUtils';\nimport { setupSceneLights } from './shared/utils/LightingUtils';\nimport type { IFactoryRegistry } from './shared/components/ComponentVisualFactory';\nimport type {\n EngineMode,\n SharedResources,\n CircuitEngineEventMap,\n EngineOptions,\n ToolType,\n} from './shared/types';\nimport { createGridHelper } from './shared/utils/GeometryUtils';\nimport { engineOptions } from './shared/utils/Options';\nimport { createMapControls } from './shared/utils/ControlsUtils';\n\n/**\n * CircuitEngine - Unified Facade for Circuit Editing and Simulation\n *\n * Manages two internal controllers:\n * - CircuitController: Static editing with tools, selection, and manipulation\n * - CircuitRunnerController: Live simulation with playback and animation\n *\n * Both controllers share the same Three.js scene, camera, and visual objects,\n * enabling seamless transitions between edit and simulation modes.\n *\n * @example\n * ```typescript\n * const engine = new CircuitEngine(factoryRegistry, behaviorRegistry);\n * engine.initialize(container);\n * engine.setCircuit(circuit);\n *\n * // Edit mode (default)\n * engine.setEditModeEnabled(true);\n * engine.setActiveTool('build');\n *\n * // Switch to simulation\n * engine.setMode('simulation');\n * engine.play();\n *\n * // Switch back to edit\n * engine.setMode('edit');\n * ```\n */\nexport class CircuitEngine extends EventEmitter<CircuitEngineEventMap> {\n // Dependencies\n private readonly _factoryRegistry: IFactoryRegistry;\n private readonly _behaviorRegistry: BehaviorRegistry;\n\n // Shared resources\n private _sharedResources: SharedResources | null = null;\n private _container: HTMLElement | null = null;\n\n // Controllers\n private _editController: CircuitController | null = null;\n private _simulationController: CircuitRunnerController | null = null;\n\n // State\n private _mode: EngineMode = 'edit';\n private _initialized: boolean = false;\n private _options: EngineOptions | null = null;\n private _disposed: boolean = false;\n\n // Event forwarding cleanup functions\n private _editControllerCleanup: (() => void) | null = null;\n private _simulationControllerCleanup: (() => void) | null = null;\n\n /**\n * Create a new CircuitEngine instance.\n *\n * @param factoryRegistry - Registry of component visual factories\n * @param behaviorRegistry - Registry of component simulation behaviors\n * @throws {TypeError} If factoryRegistry or behaviorRegistry is null/undefined\n */\n constructor(factoryRegistry: IFactoryRegistry, behaviorRegistry: BehaviorRegistry) {\n super();\n\n if (!factoryRegistry) {\n throw new TypeError('FactoryRegistry is required');\n }\n if (!behaviorRegistry) {\n throw new TypeError('BehaviorRegistry is required');\n }\n\n this._factoryRegistry = factoryRegistry;\n this._behaviorRegistry = behaviorRegistry;\n }\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n /**\n * Check if engine is initialized\n */\n get isInitialized(): boolean {\n return this._initialized;\n }\n\n /**\n * Check if engine is disposed\n */\n get isDisposed(): boolean {\n return this._disposed;\n }\n\n /**\n * Initialize the engine with a DOM container.\n * Creates shared Three.js resources and both controllers.\n *\n * @param container - HTMLElement to mount the scene\n * @param options - Configuration options\n * @throws {TypeError} If container is not a valid HTMLElement\n * @throws {Error} If already initialized\n */\n initialize(container: HTMLElement, options?: EngineOptions): void {\n if (this._initialized) {\n throw new Error('CircuitEngine is already initialized');\n }\n if (this._disposed) {\n throw new Error('CircuitEngine has been disposed');\n }\n if (!container || !(container instanceof HTMLElement)) {\n throw new TypeError('Container must be a valid HTMLElement');\n }\n\n options = engineOptions(options);\n this._options = options;\n\n this._container = container;\n\n // Create shared resources\n this._sharedResources = this._createSharedResources(container, options);\n\n // Create controllers with shared resources\n this._editController = new CircuitController(this._factoryRegistry, this._sharedResources);\n this._simulationController = new CircuitRunnerController(\n this._factoryRegistry,\n this._behaviorRegistry,\n this._sharedResources\n );\n // Initialize both controllers\n this._editController.initialize(container, options.controllerOptions);\n this._simulationController.initialize(container, options.controllerOptions);\n\n // Setup event forwarding from both controllers\n this._setupEventForwarding();\n\n // Set initial mode\n this._mode = options?.initialMode ?? 'edit';\n if (this._mode === 'edit') {\n this._editController.setActive(true);\n } else {\n this._simulationController.setActive(true);\n }\n\n this._initialized = true;\n\n // Emit ready event\n this.emit('ready', { controllerType: 'engine' });\n }\n\n /**\n * Create shared resources for both controllers.\n */\n private _createSharedResources(container: HTMLElement, options: EngineOptions): SharedResources {\n const controllerOptions = options.controllerOptions!;\n // Create scene\n const scene = new THREE.Scene();\n scene.background = new THREE.Color(controllerOptions.backgroundColor);\n // Add default sized grid\n const grid = createGridHelper(\n 10,\n 10,\n controllerOptions.colorCenterLine!,\n controllerOptions.colorGrid!\n );\n scene.add(grid);\n setupSceneLights(scene);\n\n // Create camera\n const aspect = container.clientWidth / container.clientHeight || 1;\n const camera = createPerspectiveCamera(aspect);\n camera.layers.set(0); // main visual layer\n camera.layers.enable(1); // enode hover layer\n camera.layers.enable(2); // component hover layer\n\n // Create MapControls\n const mapControls = createMapControls(camera, container, controllerOptions.mapControls!);\n\n // Create managers\n const hoverManager = new HoverManager(scene, camera);\n const branchingPointVisualFactory = new BranchingPointVisualFactory();\n\n // Create shared visual maps\n const componentObject3Ds = new Map<UUID, THREE.Object3D>();\n const enodeObject3Ds = new Map<UUID, THREE.Object3D>();\n const wireObject3Ds = new Map<UUID, Line2>();\n\n const wireVisualManager = new WireVisualManager(componentObject3Ds, wireObject3Ds);\n wireVisualManager.setContainer(container);\n wireVisualManager.setResolution(container.clientWidth, container.clientHeight);\n wireVisualManager.setSceneAndCamera(scene, camera);\n\n return {\n scene,\n camera,\n mapControls,\n grid: grid,\n factoryRegistry: this._factoryRegistry,\n branchingPointVisualFactory,\n wireVisualManager,\n hoverManager,\n componentObject3Ds,\n enodeObject3Ds,\n wireObject3Ds,\n };\n }\n\n /**\n * Setup event forwarding from both controllers to engine.\n */\n private _setupEventForwarding(): void {\n if (this._editController) {\n this._editControllerCleanup = this._editController.onAny((event, payload) => {\n // Forward all events from edit controller\n this.emit(event as keyof CircuitEngineEventMap, payload as any);\n });\n }\n\n if (this._simulationController) {\n this._simulationControllerCleanup = this._simulationController.onAny((event, payload) => {\n // Forward all events from simulation controller\n this.emit(event as keyof CircuitEngineEventMap, payload as any);\n });\n }\n }\n\n /**\n * Teardown event forwarding cleanup.\n */\n private _teardownEventForwarding(): void {\n if (this._editControllerCleanup) {\n this._editControllerCleanup();\n this._editControllerCleanup = null;\n }\n if (this._simulationControllerCleanup) {\n this._simulationControllerCleanup();\n this._simulationControllerCleanup = null;\n }\n }\n\n /**\n * Dispose all resources and clean up.\n *\n * @throws {Error} If not initialized or already disposed\n */\n dispose(): void {\n this._checkInitialized();\n\n // Stop simulation if running\n if (this._mode === 'simulation' && this._simulationController?.isPlaying) {\n this._simulationController.pause();\n }\n\n // Teardown event forwarding\n this._teardownEventForwarding();\n\n // Dispose controllers (they won't dispose shared resources)\n if (this._editController) {\n this._editController.dispose();\n this._editController = null;\n }\n if (this._simulationController) {\n this._simulationController.dispose();\n this._simulationController = null;\n }\n\n // Dispose shared resources (we own them)\n if (this._sharedResources) {\n this._sharedResources.hoverManager.dispose();\n this._sharedResources.wireVisualManager.dispose();\n this._sharedResources.mapControls.dispose();\n\n // Clear visual maps\n this._sharedResources.componentObject3Ds.clear();\n this._sharedResources.enodeObject3Ds.clear();\n this._sharedResources.wireObject3Ds.clear();\n\n this._sharedResources = null;\n }\n\n // Clear runner\n //this._runner = null;\n\n // Clear event listeners\n this.removeAllListeners();\n\n this._disposed = true;\n this._initialized = false;\n }\n\n // ============================================================================\n // Mode Management\n // ============================================================================\n\n /**\n * Current operating mode\n */\n get mode(): EngineMode {\n return this._mode;\n }\n\n /**\n * Switch between edit and simulation modes.\n *\n * @param mode - Target mode to switch to\n * @throws {Error} If not initialized\n * @throws {Error} If switching to simulation without a circuit loaded\n */\n setMode(mode: EngineMode): void {\n this._checkInitialized();\n\n // Early return if same mode\n if (this._mode === mode) {\n return;\n }\n\n const previousMode = this._mode;\n\n if (mode === 'simulation') {\n this._transitionToSimulation();\n } else {\n this._transitionToEdit();\n }\n\n this._mode = mode;\n\n // Emit modeChanged event\n this.emit('modeChanged', { mode, previousMode });\n }\n\n /**\n * Transition from edit mode to simulation mode.\n */\n private _transitionToSimulation(): void {\n // Validate circuit is loaded\n const circuit = this._editController?.getCircuit();\n if (!circuit) {\n throw new Error('Cannot switch to simulation mode: no circuit loaded');\n }\n\n // Set edit controller inactive\n if (this._editController) {\n this._editController.setActive(false);\n }\n\n // Set simulation controller active\n if (this._simulationController) {\n this._simulationController.setActive(true);\n }\n }\n\n /**\n * Transition from simulation mode to edit mode.\n */\n private _transitionToEdit(): void {\n // Set simulation controller inactive\n if (this._simulationController) {\n this._simulationController.setActive(false);\n }\n\n // Set edit controller active\n // Note: The edit controller maintains its circuit and visuals\n if (this._editController) {\n this._editController.setActive(true);\n }\n }\n\n // ============================================================================\n // Circuit Management\n // ============================================================================\n\n /**\n * Load a circuit for editing/simulation.\n *\n * @param circuit - Circuit to load, or null to clear\n * @throws {Error} If not initialized\n */\n setCircuit(circuit: Circuit | null): void {\n this._checkInitialized();\n const options = this._options || engineOptions();\n\n if (this._sharedResources?.grid) {\n this._sharedResources?.grid?.dispose();\n this._sharedResources?.scene.remove(this._sharedResources?.grid);\n }\n\n // Load circuit via edit controller\n if (this._editController) {\n this._editController.setCircuit(circuit);\n this._simulationController?.setCircuit(circuit);\n }\n\n const gridSize = circuit ? circuit.metadata.size : 10;\n const gridDivisions = circuit ? circuit.metadata.divisions : 10;\n this._sharedResources!.grid = createGridHelper(\n gridSize,\n gridDivisions,\n options.controllerOptions!.colorCenterLine!,\n options.controllerOptions!.colorGrid!\n );\n this._sharedResources?.scene.add(this._sharedResources!.grid);\n\n if (circuit && this._sharedResources?.camera) {\n updateCamera(this._sharedResources?.camera, circuit.metadata.cameraOptions);\n }\n if (circuit && this._sharedResources?.mapControls) {\n const controls = this._sharedResources?.mapControls;\n const target = circuit.metadata.cameraOptions.lookAtPosition;\n controls.target.set(target.x, target.y, target.z);\n }\n }\n\n /**\n * Get the currently loaded circuit\n */\n getCircuit(): Circuit | null {\n this._checkInitialized();\n return this._editController?.getCircuit() ?? null;\n }\n\n // ============================================================================\n // Controllers Access\n // ============================================================================\n\n /**\n * Get the edit controller for advanced operations.\n *\n * @throws {Error} If not initialized\n */\n getEditController(): CircuitController {\n this._checkInitialized();\n return this._editController!;\n }\n\n /**\n * Get the simulation controller for advanced operations.\n *\n * @throws {Error} If not initialized\n */\n getSimulationController(): CircuitRunnerController {\n this._checkInitialized();\n return this._simulationController!;\n }\n\n // ============================================================================\n // Edit Mode Operations\n // ============================================================================\n\n /**\n * Activate an editing tool.\n *\n * @param toolType - Tool to activate\n * @throws {Error} If not in edit mode\n */\n setActiveTool(toolType: ToolType): void {\n this._checkEditMode();\n this._editController!.setActiveTool(toolType);\n }\n\n /**\n * Get the currently active tool\n *\n * @throws {Error} If not in edit mode\n */\n getActiveTool(): ToolType | null {\n this._checkEditMode();\n return this._editController!.getActiveTool();\n }\n\n /**\n * Enable or disable edit mode (tool system).\n *\n * @param enabled - True to enable, false to disable\n * @throws {Error} If not in edit mode\n */\n setEditModeEnabled(enabled: boolean): void {\n this._checkEditMode();\n this._editController!.setEditMode(enabled);\n }\n\n // ============================================================================\n // Simulation Mode Operations\n // ============================================================================\n\n /**\n * Start automatic simulation playback.\n *\n * @throws {Error} If not in simulation mode\n */\n play(): void {\n this._checkSimulationMode();\n this._simulationController!.play();\n }\n\n /**\n * Pause automatic simulation playback.\n *\n * @throws {Error} If not in simulation mode\n */\n pause(): void {\n this._checkSimulationMode();\n this._simulationController!.pause();\n }\n\n /**\n * Execute a single simulation tick.\n *\n * @throws {Error} If not in simulation mode\n */\n step(): void {\n this._checkSimulationMode();\n this._simulationController!.step();\n }\n\n /**\n * Stop simulation and reset to initial state.\n *\n * @throws {Error} If not in simulation mode\n */\n stop(): void {\n this._checkSimulationMode();\n this._simulationController!.stop();\n }\n\n /**\n * Check if simulation is currently playing\n */\n get isPlaying(): boolean {\n if (this._mode !== 'simulation') {\n return false;\n }\n return this._simulationController?.isPlaying ?? false;\n }\n\n /**\n * Get current simulation tick\n */\n get currentTick(): number {\n if (this._mode !== 'simulation') {\n return 0;\n }\n return this._simulationController?.currentTick ?? 0;\n }\n\n /**\n * Tick interval in milliseconds\n */\n get tickInterval(): number {\n return this._simulationController?.tickInterval ?? 500;\n }\n\n set tickInterval(value: number) {\n if (this._simulationController) {\n this._simulationController.tickInterval = value;\n }\n }\n\n /**\n * Simulation speed in ticks per second.\n * Range: 1-20 TPS. Works in both edit and simulation modes.\n */\n get simulationSpeed(): number {\n return this._simulationController?.simulationSpeed ?? 2;\n }\n\n set simulationSpeed(tps: number) {\n if (this._simulationController) {\n this._simulationController.simulationSpeed = tps;\n }\n }\n\n /**\n * Minimum allowed simulation speed in ticks per second.\n */\n get minSimulationSpeed(): number {\n return this._simulationController?.minSimulationSpeed ?? 1;\n }\n\n /**\n * Maximum allowed simulation speed in ticks per second.\n */\n get maxSimulationSpeed(): number {\n return this._simulationController?.maxSimulationSpeed ?? 20;\n }\n\n // ============================================================================\n // Three.js Access\n // ============================================================================\n\n /**\n * Get the Three.js scene for external rendering.\n *\n * @throws {Error} If not initialized\n */\n getScene(): THREE.Scene {\n this._checkInitialized();\n return this._sharedResources!.scene;\n }\n\n /**\n * Get the camera for external rendering.\n *\n * @throws {Error} If not initialized\n */\n getCamera(): THREE.PerspectiveCamera {\n this._checkInitialized();\n return this._sharedResources!.camera;\n }\n\n /**\n * Get the MapControls for external manipulation.\n *\n * @throws {Error} If not initialized\n */\n getControls(): MapControls {\n this._checkInitialized();\n return this._sharedResources!.mapControls;\n }\n\n /**\n * Hook called before exporting the circuit visualization.\n * Saves world informations such as camera position, in the circuit metadata.\n */\n public beforeExport(): void {\n if (!this._editController) return;\n this._editController.beforeExport();\n }\n\n /**\n * Handle container resize.\n *\n * @param width - New width (optional, uses container if omitted)\n * @param height - New height (optional, uses container if omitted)\n */\n onContainerResize(width?: number, height?: number): void {\n this._checkInitialized();\n\n const w = width ?? this._container!.clientWidth;\n const h = height ?? this._container!.clientHeight;\n\n // Update camera\n const camera = this._sharedResources!.camera;\n camera.aspect = w / h;\n camera.updateProjectionMatrix();\n\n // Update wire visual manager resolution\n this._sharedResources!.wireVisualManager.setResolution(w, h);\n\n // Delegate to active controller for any additional resize handling\n if (this._mode === 'edit' && this._editController) {\n this._editController.onContainerResize(w, h);\n } else if (this._mode === 'simulation' && this._simulationController) {\n this._simulationController.onContainerResize(w, h);\n }\n }\n\n // ============================================================================\n // Internal Helpers\n // ============================================================================\n\n /**\n * Check that controller is initialized and not disposed.\n *\n * @throws {Error} If not initialized or disposed\n */\n private _checkInitialized(): void {\n if (this._disposed) {\n throw new Error('CircuitEngine has been disposed');\n }\n if (!this._initialized) {\n throw new Error('CircuitEngine is not initialized');\n }\n }\n\n /**\n * Check that controller is in edit mode.\n *\n * @throws {Error} If not in edit mode\n */\n private _checkEditMode(): void {\n this._checkInitialized();\n if (this._mode !== 'edit') {\n throw new Error('Operation not available: not in edit mode');\n }\n }\n\n /**\n * Check that engine is in simulation mode.\n *\n * @throws {Error} If not in simulation mode\n */\n private _checkSimulationMode(): void {\n this._checkInitialized();\n if (this._mode !== 'simulation') {\n throw new Error('Operation not available: not in simulation mode');\n }\n }\n}\n","/**\n * Factory Registry Implementation\n * @module scene/shared/FactoryRegistry\n *\n * Manages registration and retrieval of component visual factories\n * with fallback support for unknown component types.\n */\n\nimport type { ComponentType } from 'simple-circuit-engine/core';\nimport type { IComponentVisualFactory, IFactoryRegistry } from './ComponentVisualFactory';\n\n/**\n * Registry mapping ComponentType to ComponentVisualFactory\n *\n * Provides type-safe registration and retrieval with automatic fallback.\n * Supports both function-based (legacy) and class-based (new) factories.\n * Thread-safe for read operations (get/has), write operations should be\n * performed during initialization.\n *\n * @example\n * ```typescript\n * const registry = new FactoryRegistry(new DefaultVisualFactory());\n * registry.register(ComponentType.Battery, new BatteryVisualFactory());\n * registry.register(ComponentType.LED, new SmallLEDVisualFactory());\n *\n * const factory = registry.get(ComponentType.Battery); // Returns BatteryVisualFactory\n * const unknown = registry.get(ComponentType.Unknown); // Returns fallback\n * const mesh = factory.createVisual(component);\n * ```\n */\nexport class FactoryRegistry implements IFactoryRegistry {\n private factories: Map<ComponentType, IComponentVisualFactory> = new Map();\n private fallbackFactory: IComponentVisualFactory;\n\n /**\n * Create a new factory registry\n *\n * @param fallbackFactory - Factory to use for unregistered component types\n * @throws {TypeError} If fallbackFactory is null or undefined\n */\n constructor(fallbackFactory: IComponentVisualFactory) {\n if (!fallbackFactory) {\n throw new TypeError('FactoryRegistry requires a valid fallback factory');\n }\n this.fallbackFactory = fallbackFactory;\n }\n\n /**\n * Register a visual factory for a specific component type\n *\n * @param type - Component type identifier\n * @param factory - Factory (class instance or function) to create visuals for this type\n * @throws {TypeError} If type is empty/whitespace or factory is null/undefined\n * @returns This FactoryRegistry instance (for chaining)\n */\n register(type: ComponentType, factory: IComponentVisualFactory): FactoryRegistry {\n if (typeof type !== 'string' || type.trim() === '') {\n throw new TypeError('Component type must be a non-empty string');\n }\n if (!factory) {\n throw new TypeError(`Factory cannot be null or undefined for type: ${type}`);\n }\n // Accept both class instances (object with createVisual method) and functions\n if (typeof factory !== 'object' || typeof (factory as any).createVisual !== 'function') {\n throw new TypeError(\n `Factory must be a an object with createVisual method for type: ${type}`\n );\n }\n this.factories.set(type, factory);\n return this;\n }\n\n /**\n * Retrieve the factory for a component type\n *\n * @param type - Component type identifier\n * @returns Factory (fallback factory if type not registered)\n *\n * @remarks\n * This method NEVER returns null/undefined. If the type is not registered,\n * the fallback factory provided in the constructor is returned.\n */\n get(type: ComponentType): IComponentVisualFactory {\n return this.factories.get(type) ?? this.fallbackFactory;\n }\n\n /**\n * Check if a factory is registered for a component type\n *\n * @param type - Component type identifier\n * @returns true if explicitly registered, false if would use fallback\n */\n has(type: ComponentType): boolean {\n return this.factories.has(type);\n }\n\n /**\n * Get the fallback factory used for unregistered types\n */\n getFallbackFactory(): IComponentVisualFactory {\n return this.fallbackFactory;\n }\n\n /**\n * Unregister a factory for a component type\n *\n * @param type - Component type identifier\n * @returns true if factory was registered and removed, false otherwise\n *\n * @remarks\n * After unregistering, get() will return the fallback factory for this type.\n */\n unregister(type: ComponentType): boolean {\n return this.factories.delete(type);\n }\n\n /**\n * Get all registered component types\n *\n * @returns Array of ComponentType values that have registered factories\n */\n getRegisteredTypes(): ComponentType[] {\n return Array.from(this.factories.keys());\n }\n}\n","/**\n * Component Visual Factory System\n * @module scene/shared/ComponentVisualFactory\n *\n * Provides factory pattern for creating Three.js visuals from Circuit components.\n * Supports dynamic registration and fallback for unknown component types.\n */\n\nimport type { Component, ComponentType, ComponentState } from 'simple-circuit-engine/core';\nimport { ENodeSourceType } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { HitboxLayers } from '../utils/LayerConstants';\n\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Interface for component visual factories\n *\n * Implementations provide methods for:\n * - Creating the 3D visual representation\n * - Applying/removing hover effects\n * - Applying/removing selection effects\n * - Updating animation based on simulation state\n *\n * @example\n * ```typescript\n * class MyComponentFactory extends ComponentVisualFactoryBase {\n * createVisual(component: Component): THREE.Object3D {\n * const group = new THREE.Group();\n * // ... create visual elements\n * group.userData.componentId = component.id;\n * group.userData.componentType = component.type;\n * return group;\n * }\n * }\n * ```\n */\nexport interface IComponentVisualFactory {\n /**\n * Create the Three.js visual representation for a component\n *\n * @param component - The circuit component to visualize\n * @returns THREE.Object3D (typically a Group) containing the visual\n *\n * @remarks\n * Implementations MUST:\n * - Set `object.userData.componentId = component.id`\n * - Set `object.userData.componentType = component.type`\n * - Create component hitbox on HitboxLayers.COMPONENT layer\n * - Create pin groups with enodes on HitboxLayers.ENODE layer\n * - Return objects positioned at origin (scene controllerType handles placement)\n */\n createVisual(component: Component): THREE.Object3D;\n\n /**\n * Update visual based on component configuration\n *\n * @param object3D - The Object3D created by createVisual()\n * @param config - The core component configuration Map\n *\n */\n updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>): void;\n\n /**\n * Apply hover visual effect to a component's Object3D\n *\n * @param object3D - The Object3D created by createVisual()\n *\n * @remarks\n * - Should store original material state in userData for restoration\n * - Default implementation: emissive glow effect (light blue, 0.5 intensity)\n * - Called by scene controllerType when component is hovered\n * - Should be idempotent (safe to call multiple times)\n */\n applyHover(object3D: THREE.Object3D): void;\n\n /**\n * Remove hover visual effect from a component's Object3D\n *\n * @param object3D - The Object3D created by createVisual()\n *\n * @remarks\n * - Should restore original material state from userData\n * - Called by scene controllerType when hover ends\n * - Should be safe to call even if not currently hovered\n */\n removeHover(object3D: THREE.Object3D): void;\n\n /**\n * Apply selection visual effect to a component's Object3D\n *\n * @param object3D - The Object3D created by createVisual()\n *\n * @remarks\n * - Currently a placeholder (no-op) for future implementation\n */\n applySelection(object3D: THREE.Object3D): void;\n\n /**\n * Remove selection visual effect from a component's Object3D\n *\n * @param object3D - The Object3D created by createVisual()\n *\n * @remarks\n * - Currently a placeholder (no-op) for future implementation\n */\n removeSelection(object3D: THREE.Object3D): void;\n\n /**\n * Update pin source type visual (optional method)\n *\n * @param pinGroup - The THREE.Group containing the pin visual\n * @param sourceType - The new source type (null for no source)\n *\n * @remarks\n * - Optional method for component factories that support pin source type visualization\n * - Changes pin color based on source type (bronze/red/blue)\n * - Default implementation in ComponentVisualFactoryBase\n */\n updatePinSourceType(pinGroup: THREE.Object3D, sourceType: ENodeSourceType | null): void;\n\n /**\n * Apply hover effect on a pin\n * @param pinGroup\n */\n applyPinHover(pinGroup: THREE.Object3D): void;\n\n /**\n * Remove hover effect on a pin\n */\n removePinHover(pinGroup: THREE.Object3D): void;\n\n /**\n * Update animation state based on simulation data\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The component's current simulation state or null to reset to edition mode\n *\n * @remarks\n * - Called by CircuitRunnerController during simulation\n * - Animation visual updates have priority over hover effects\n * - Default implementation: no-op (static components)\n * - Subclasses override for component-specific animation\n * (e.g., LED glow, switch contactor rotation)\n */\n updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void;\n\n /**\n * Get the config form definition for this component type\n *\n * @returns Form definition with field specifications, or null if no config\n *\n * @remarks\n * Defines the UI controls for editing component configuration.\n * Return null for components with no configurable options.\n */\n getConfigFormDefinition(): ConfigFormDefinition | null;\n\n /**\n * Map core component config (string values) to form data (typed values)\n *\n * @param config - Core config from Component.config\n * @returns Form data with appropriate types for UI controls\n *\n * @remarks\n * Called when config panel opens to initialize form controls.\n * Converts core string values to UI-appropriate types (e.g., \"open\" → true).\n */\n mapCoreConfigToForm(config: Map<string, string>): Map<string, any>;\n\n /**\n * Map form data (typed values) back to core config (string values)\n *\n * @param formData - Current form values from UI\n * @returns Core config ready for Component.setAllParameters()\n *\n * @remarks\n * Called on each value change to update Component.config.\n * Converts UI values back to core string format (e.g., true → \"open\").\n */\n mapFormToCoreConfig(formData: Map<string, any>): Map<string, string>;\n}\n\n/**\n * Abstract base class for component visual factories\n *\n * Provides default implementations for:\n * - Hover effect (emissive glow)\n * - Selection effect (placeholder/no-op)\n * - Animation update (placeholder/no-op)\n * - Pin group creation (shared helper)\n * - Component hitbox creation (shared helper)\n *\n * Subclasses must implement:\n * - createVisual() - component-specific visual creation\n *\n * Subclasses may override:\n * - applyHover() / removeHover() - custom hover effect\n * - applySelection() / removeSelection() - custom selection effect (future)\n * - updateAnimation() - component-specific animation\n *\n * @example\n * ```typescript\n * export class BatteryVisualFactory extends ComponentVisualFactoryBase {\n * createVisual(component: Component): THREE.Object3D {\n * const group = new THREE.Group();\n * // ... create battery-specific visual\n * return group;\n * }\n * // Inherits default hover, selection, and animation\n * }\n * ```\n */\nexport abstract class ComponentVisualFactoryBase implements IComponentVisualFactory {\n /** Default hover glow color (light blue) */\n protected static readonly DEFAULT_HOVER_COLOR = 0x4488ff;\n\n /** Default hover emissive intensity */\n protected static readonly DEFAULT_HOVER_INTENSITY = 0.6;\n\n /** Default selection glow color (orange) */\n protected static readonly DEFAULT_SELECTION_COLOR = 0xff8800;\n\n /** Default selection emissive intensity (higher than hover) */\n protected static readonly DEFAULT_SELECTION_INTENSITY = 0.8;\n\n /**\n * Create the Three.js visual representation for a component\n * Must be implemented by subclasses\n */\n abstract createVisual(component: Component): THREE.Object3D;\n\n /**\n * By default no visual configuration-based updates is needed\n */\n updateFromConfiguration(_object3D: THREE.Object3D, _config: Map<string, string>) {\n // Default: no-op\n }\n\n /**\n * Apply hover visual effect using emissive glow\n *\n * Default implementation traverses all meshes and applies\n * an emissive blue glow effect, storing original values in userData.\n *\n * Note: If component is selected, selection visual takes precedence\n * and hover visual is not applied (but isHovered flag is still set).\n */\n applyHover(object3D: THREE.Object3D): void {\n if (object3D.userData.isSelected) {\n // Component is selected; skip hover visual\n return;\n }\n\n object3D.traverse((child) => {\n if (child.userData.type === 'enodeHitbox' || child.userData.type === 'enode') {\n return;\n }\n if (child.userData.type === 'enodeGroup') {\n this.applyPinHover(child);\n return;\n }\n if (!(child instanceof THREE.Mesh)) return;\n if (child.userData.materialLocked) return; // this flag indicates material is locked by animation\n\n const material = child.material;\n if (material.visible === false) return;\n if (!(material instanceof THREE.MeshStandardMaterial)) return;\n material.emissive.setHex(ComponentVisualFactoryBase.DEFAULT_HOVER_COLOR);\n material.emissiveIntensity = ComponentVisualFactoryBase.DEFAULT_HOVER_INTENSITY;\n });\n }\n\n /**\n * Remove hover visual effect, restoring original materials\n */\n removeHover(object3D: THREE.Object3D): void {\n if (object3D.userData.isSelected) {\n // Component is selected; skip unhover visual\n return;\n }\n object3D.traverse((child) => {\n if (child.userData.type === 'enodeHitbox' || child.userData.type === 'enode') {\n return;\n }\n if (child.userData.type === 'enodeGroup') {\n this.removePinHover(child);\n return;\n }\n if (!(child instanceof THREE.Mesh)) return;\n if (child.userData.materialLocked) return; // this flag indicates material is locked by animation\n\n const material = child.material;\n if (!(material instanceof THREE.MeshStandardMaterial)) return;\n material.emissiveIntensity = 0;\n });\n }\n\n /**\n * Apply selection visual effect using emissive orange glow\n *\n * Selection takes precedence over hover effect.\n * Stores original material state in userData for restoration.\n *\n * @param object3D - The component's root Three.js object\n */\n applySelection(object3D: THREE.Object3D): void {\n object3D.traverse((child) => {\n if (child.userData.type === 'enodeHitbox' || child.userData.type === 'enode') {\n return;\n }\n if (child.userData.type === 'enodeGroup') {\n this.removePinHover(child);\n return;\n }\n if (!(child instanceof THREE.Mesh)) return;\n const material = child.material;\n if (material.visible === false || material.opacity < 0.5) return;\n if (!(material instanceof THREE.MeshStandardMaterial)) return;\n // Apply selection effect (overrides hover if present)\n material.emissive.setHex(ComponentVisualFactoryBase.DEFAULT_SELECTION_COLOR);\n material.emissiveIntensity = ComponentVisualFactoryBase.DEFAULT_SELECTION_INTENSITY;\n });\n\n object3D.userData.isSelected = true;\n }\n\n /**\n * Remove selection visual effect, restoring original or hover state\n *\n * If component was hovered before selection, restores hover visual.\n * Otherwise, restores original material state.\n *\n * @param object3D - The component's root Three.js object\n */\n removeSelection(object3D: THREE.Object3D): void {\n object3D.traverse((child) => {\n if (child.userData.type === 'enodeHitbox' || child.userData.type === 'enode') {\n return;\n }\n if (child.userData.type === 'enodeGroup') {\n this.removePinHover(child);\n return;\n }\n if (!(child instanceof THREE.Mesh)) return;\n const material = child.material;\n if (material.visible === false || material.opacity < 0.5) return;\n if (!(material instanceof THREE.MeshStandardMaterial)) return;\n // remove selection effect\n material.emissiveIntensity = 0;\n });\n object3D.userData.isSelected = false;\n }\n\n /**\n * Create a pin group with hitbox and visual sphere\n *\n * Creates a THREE.Group containing:\n * - Hemisphere hitbox (on ENODE layer for raycasting)\n * - Hemisphere visual (blue sphere)\n * - Hover callback in userData\n *\n * @param componentId - UUID of the parent component\n * @param pinId - UUID of this pin/enode\n * @param label - Human-readable label (e.g., 'input', 'output', 'cathode')\n * @param sourceType - Optional source type (voltage/current) : if provided this pin will be locked to that type\n * @returns THREE.Group configured as pin group\n */\n protected createPinGroup(\n componentId: string,\n pinId: string,\n label: string,\n sourceType: ENodeSourceType | null = null\n ): THREE.Group {\n const pinGroup = new THREE.Group();\n pinGroup.userData = {\n type: 'enodeGroup',\n componentId: componentId,\n enodeId: pinId,\n label: label,\n lockedSourceType: sourceType,\n };\n\n // Hitbox (hemisphere, raycastable)\n const hitboxGeom = new THREE.SphereGeometry(0.9, 16, 8, 0, Math.PI * 2, 0, Math.PI / 2);\n const hitbox = new THREE.Mesh(\n hitboxGeom,\n new THREE.MeshStandardMaterial({\n color: ComponentVisualFactoryBase.DEFAULT_HOVER_COLOR,\n transparent: true,\n opacity: 0,\n })\n );\n hitbox.userData = {\n type: 'enodeHitbox',\n componentId: componentId,\n enodeId: pinId,\n label: label,\n lockedSourceType: sourceType,\n };\n hitbox.layers.set(HitboxLayers.ENODE);\n pinGroup.add(hitbox);\n\n // Visual sphere\n const visual = new THREE.Mesh(\n new THREE.SphereGeometry(0.3, 16, 8, 0, Math.PI * 2, 0, Math.PI / 2),\n new THREE.MeshStandardMaterial({\n color: this.pinColorForSourceType(sourceType),\n emissive: this.pinColorForSourceType(sourceType),\n emissiveIntensity: 0,\n })\n );\n visual.userData = {\n type: 'enode',\n componentId: componentId,\n enodeId: pinId,\n label: label,\n lockedSourceType: sourceType,\n };\n pinGroup.add(visual);\n\n return pinGroup;\n }\n\n /**\n * Find pin group by label within a component Object3D\n * @param object3D\n * @param label\n */\n findPinGroup(object3D: THREE.Object3D, label: string): THREE.Group | null {\n let pinGroup: THREE.Group | null = null;\n object3D.traverse((child) => {\n if (\n child.userData.type === 'enodeGroup' &&\n child.userData.label === label &&\n child instanceof THREE.Group\n ) {\n pinGroup = child;\n }\n });\n return pinGroup;\n }\n\n /**\n * Create component hitbox mesh\n *\n * Helper to create standard component hitbox with proper userData and layer.\n *\n * @param componentId - UUID of the component\n * @param groupId - ID of the parent THREE.Group\n * @param width - Hitbox width\n * @param height - Hitbox height\n * @param depth - Hitbox depth\n * @returns THREE.Mesh configured as component hitbox\n */\n protected createComponentHitbox(\n componentId: string,\n groupId: number,\n width: number,\n height: number,\n depth: number\n ): THREE.Mesh {\n const geometry = new THREE.BoxGeometry(width, height, depth);\n const material = new THREE.MeshBasicMaterial({\n color: 0xffff00,\n transparent: true,\n opacity: 0,\n visible: false,\n });\n const hitbox = new THREE.Mesh(geometry, material);\n hitbox.userData = {\n type: 'componentHitbox',\n componentId: componentId,\n groupId: groupId,\n };\n hitbox.layers.set(HitboxLayers.COMPONENT);\n return hitbox;\n }\n\n protected findHitbox(object3D: THREE.Object3D): THREE.Mesh | null {\n let hitbox: THREE.Mesh | null = null;\n object3D.traverse((child) => {\n if (child.userData.type === 'componentHitbox' && child instanceof THREE.Mesh) {\n hitbox = child;\n }\n });\n return hitbox;\n }\n\n protected pinColorForSourceType(sourceType: ENodeSourceType | null): number {\n if (!sourceType) {\n return 0xb87333; // Bronze for no source\n }\n if (sourceType === ENodeSourceType.Voltage) {\n return 0xff0000; // Red for voltage\n } else if (sourceType === ENodeSourceType.Current) {\n return 0x0000ff; // Blue for current\n }\n return 0xb87333; // Bronze by default\n }\n\n protected pinColorForElectricalState(state: 'current' | 'voltage' | 'vc' | 'idle'): number {\n switch (state) {\n case 'voltage':\n return 0xff0000; // Red\n case 'current':\n return 0x0000ff; // Blue\n case 'vc':\n return 0xcc00cc; // Magenta\n case 'idle':\n default:\n return 0x000000;\n }\n }\n\n /**\n * Updates the visual color of a component pin based on its source type.\n *\n * This method changes the pin's material color to reflect the source type:\n * - null/undefined: bronze (default pin color)\n * - Voltage: red\n * - Current: blue\n *\n * @param pinGroup - The THREE.Group containing the pin visual (created by createPinGroup)\n * @param sourceType - The new source type (null for no source)\n *\n * @remarks\n * - Searches for the child mesh with userData.type === 'enode'\n * - Updates both color and emissive properties for visual consistency\n * - If sourceType is null/undefined, restores default bronze pin color\n * - Color scheme matches BranchingPointVisualFactory for consistency\n */\n updatePinSourceType(pinGroup: THREE.Object3D, sourceType: ENodeSourceType | null): void {\n if (!!pinGroup.userData.lockedSourceType) return; // Pin is locked to a source type, do not change color\n pinGroup.userData.sourceType = sourceType;\n\n const visual = pinGroup.children.find((child) => child.userData.type === 'enode') as\n | THREE.Mesh\n | undefined;\n\n if (!visual || !(visual.material instanceof THREE.MeshStandardMaterial)) {\n return;\n }\n const color = this.pinColorForSourceType(sourceType);\n visual.material.color.setHex(color);\n visual.material.emissive.setHex(color);\n }\n\n /**\n * Apply hover visual effect on this pin\n */\n applyPinHover(pinGroup: THREE.Object3D): void {\n if (pinGroup.userData.isHovered) {\n return; // Already hovered\n }\n pinGroup.userData.isHovered = true;\n\n pinGroup.traverse((child) => {\n if (child instanceof THREE.Mesh) {\n const material = child.material as THREE.MeshStandardMaterial;\n\n if (child.userData.type === 'enodeHitbox') {\n material.opacity = 0.3;\n } else if (child.userData.type === 'enode') {\n material.color.setHex(0x00ff00);\n // Apply hover effect\n material.emissiveIntensity = 0.9;\n }\n }\n });\n }\n\n /**\n * remove hover visual effect on this pin\n */\n removePinHover(pinGroup: THREE.Object3D): void {\n if (!pinGroup.userData.isHovered) {\n return; // Already hovered\n }\n pinGroup.userData.isHovered = false;\n\n const sourceType: ENodeSourceType | null =\n pinGroup.userData.lockedSourceType || pinGroup.userData.sourceType || null;\n\n pinGroup.traverse((child) => {\n if (child instanceof THREE.Mesh) {\n const material = child.material as THREE.MeshStandardMaterial;\n\n if (child.userData.type === 'enodeHitbox') {\n material.opacity = 0;\n } else if (child.userData.type === 'enode') {\n material.color.setHex(this.pinColorForSourceType(sourceType));\n material.emissiveIntensity = sourceType ? 1 : 0;\n if (!sourceType && pinGroup.userData.electricalState) {\n const emissiveColor = this.pinColorForElectricalState(\n pinGroup.userData.electricalState\n );\n material.emissive.setHex(emissiveColor);\n material.emissiveIntensity = emissiveColor === 0x000000 ? 0 : 1;\n }\n }\n }\n });\n }\n\n /**\n * Update animation state based on simulation data (placeholder)\n *\n * Default implementation is a no-op for static components.\n * Override in subclasses that have animation (LED, Switch).\n */\n updateAnimation(_object3D: THREE.Object3D, _state: ComponentState | null): void {\n // Default: no-op for static components\n // Subclasses override for component-specific animation\n }\n\n /**\n * Get config form definition (default: null - no config)\n *\n * Override in subclasses that have configurable options.\n */\n getConfigFormDefinition(): ConfigFormDefinition | null {\n return null;\n }\n\n /**\n * Map core config to form data (default: identity mapping)\n *\n * Override in subclasses that need type conversions.\n */\n mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n return new Map(config);\n }\n\n /**\n * Map form data to core config (default: convert all to strings)\n *\n * Override in subclasses that need type conversions.\n */\n mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n for (const [key, value] of formData.entries()) {\n config.set(key, String(value));\n }\n return config;\n }\n}\n\n/**\n * Registry interface for managing component visual factories\n *\n * Provides type-safe registration and retrieval of component factories.\n * Falls back to a default factory for unregistered component types.\n *\n * @remarks\n * Updated to support both function-based and class-based factories.\n * Prefer using IComponentVisualFactory class instances.\n *\n * @example\n * ```typescript\n * const registry = new FactoryRegistry(new DefaultVisualFactory());\n * registry.register(ComponentType.Battery, new BatteryVisualFactory());\n * registry.register(ComponentType.LED, new SmallLEDVisualFactory());\n *\n * const factory = registry.get(ComponentType.Battery);\n * const mesh = factory.createVisual(batteryComponent);\n * ```\n */\nexport interface IFactoryRegistry {\n /**\n * Register a visual factory for a specific component type\n *\n * @param type - Component type identifier\n * @param factory - Factory (class instance or function) to create visuals for this type\n * @throws {TypeError} If factory is null or undefined\n * @returns This IFactoryRegistry instance (for chaining)\n */\n register(type: ComponentType, factory: IComponentVisualFactory): IFactoryRegistry;\n\n /**\n * Retrieve the factory for a component type\n *\n * @param type - Component type identifier\n * @returns Factory (fallback factory if type not registered)\n *\n * @remarks\n * This method NEVER returns null/undefined. If the type is not registered,\n * the fallback factory provided in the constructor is returned.\n */\n get(type: ComponentType): IComponentVisualFactory;\n\n /**\n * Check if a factory is registered for a component type\n *\n * @param type - Component type identifier\n * @returns true if explicitly registered, false if would use fallback\n */\n has(type: ComponentType): boolean;\n\n /**\n * Get the fallback factory used for unregistered component types\n */\n getFallbackFactory(): IComponentVisualFactory;\n\n /**\n * Unregister a factory for a component type\n *\n * @param type - Component type identifier\n * @returns true if factory was registered and removed, false otherwise\n *\n * @remarks\n * After unregistering, get() will return the fallback factory for this type.\n */\n unregister(type: ComponentType): boolean;\n\n /**\n * Get all registered component types\n *\n * @returns Array of ComponentType values that have registered factories\n */\n getRegisteredTypes(): ComponentType[];\n}\n","/**\n * Color utilities\n * @module scene/shared/utils/ColorUtils\n */\n\n/**\n * Standard color presets for hybrid color controls\n */\nexport const COLOR_PRESETS: Readonly<Record<string, string>> = {\n red: '#ff0000',\n green: '#00ff00',\n blue: '#0000ff',\n yellow: '#ffff00',\n orange: '#ff8800',\n purple: '#8800ff',\n cyan: '#00ffff',\n magenta: '#ff00ff',\n white: '#ffffff',\n black: '#000000',\n};\n\n/**\n * Check if a color value is a hex string\n * @param value - Color value to check\n * @returns true if value matches #RRGGBB format\n */\nexport function isHexColor(value: string): boolean {\n return /^#[0-9A-Fa-f]{6}$/.test(value);\n}\n\n/**\n * Convert a hex color to preset name if it matches, otherwise return hex\n * @param hex - Hex color string (e.g., \"#ff0000\")\n * @returns Preset name if match found, otherwise the hex string\n */\nexport function hexToPresetOrHex(hex: string): string {\n const lowerHex = hex.toLowerCase();\n for (const [name, presetHex] of Object.entries(COLOR_PRESETS)) {\n if (presetHex.toLowerCase() === lowerHex) {\n return name;\n }\n }\n return hex;\n}\n\n/**\n * Convert a preset name or hex to hex value\n * @param value - Preset name (e.g., \"red\") or hex string (e.g., \"#ff0000\")\n * @returns Hex color string\n */\nexport function presetOrHexToHex(value: string): string {\n if (isHexColor(value)) {\n return value;\n }\n return COLOR_PRESETS[value] ?? '#ffffff';\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component } from 'simple-circuit-engine/core';\nimport { presetOrHexToHex, hexToPresetOrHex } from '../utils/ColorUtils';\nimport * as THREE from 'three';\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Default Visual factory for not yet defined components\n *\n * Creates:\n * - Box squared mesh (white)\n * - Component hitbox for raycasting\n *\n * This default visual is pinless no matter the component definition.\n */\nexport class DefaultVisualFactory extends ComponentVisualFactoryBase {\n createVisual(component: Component): THREE.Object3D {\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n isPlaceholder: true,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 2, 2, 2);\n group.add(hitbox);\n\n // Visual box\n const boxGeometry = new THREE.BoxGeometry(0.5, 0.5, 0.5, 4, 4, 4);\n const boxMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const box = new THREE.Mesh(boxGeometry, boxMaterial);\n box.userData = {\n type: 'component',\n componentId: component.id,\n };\n group.add(box);\n\n return group;\n }\n\n /**\n * Get config form definition (T028)\n * Returns form for Cube (color) - RectangleLED uses SmallLEDVisualFactory\n *\n * @returns Form definition with color field for Cube\n */\n override getConfigFormDefinition(): ConfigFormDefinition | null {\n // Default factory is used for Cube, which has a simple color config\n return {\n fields: [{ key: 'color', label: 'Color', type: 'color' }],\n };\n }\n\n /**\n * Map core config to form data (T028)\n * Converts hex/preset strings to hex values for color picker\n *\n * @param config - Core component config\n * @returns Form data with hex color string\n */\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n const color = config.get('color') || '#ffffff';\n\n // Convert preset names to hex if needed\n formData.set('color', presetOrHexToHex(color));\n\n return formData;\n }\n\n /**\n * Map form data to core config (T028)\n * Converts hex colors to preset names if they match, otherwise keeps hex\n *\n * @param formData - Form data with hex color string\n * @returns Core config with hex or preset name string\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n const color = formData.get('color');\n\n // Convert hex to preset name if it matches a preset\n if (color) {\n config.set('color', hexToPresetOrHex(color));\n }\n\n return config;\n }\n\n /**\n * Update visual from configuration (T023)\n * Updates Cube/RectangleLED color based on color config\n *\n * @param object3D - The Object3D created by createVisual()\n * @param config - Component configuration map\n *\n * @remarks\n * Updates the box mesh color if 'color' config exists\n * Supports both hex colors and color presets\n */\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>): void {\n const color = config.get('color');\n if (!color) return;\n\n // Find the box mesh\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.type === 'component') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n // Convert preset to hex if needed, then parse\n const hexColor = presetOrHexToHex(color);\n const colorHex = parseInt(hexColor.replace('#', ''), 16);\n child.material.color.setHex(colorHex);\n }\n }\n });\n }\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component } from 'simple-circuit-engine/core';\nimport { ENodeSourceType } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\n\n/**\n * Visual factory for Battery components\n *\n * Creates:\n * - Cylinder mesh (white) for battery body\n * - Cathode pin group at z=-1\n * - Anode pin group at z=+1\n * - Component hitbox for raycasting\n */\nexport class BatteryVisualFactory extends ComponentVisualFactoryBase {\n createVisual(component: Component): THREE.Object3D {\n // Root group (not rendered, just organizational)\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 2, 2, 3);\n group.add(hitbox);\n\n // Visual: battery cylinder\n const cylinderGeometry = new THREE.CylinderGeometry(0.5, 0.5, 2, 24);\n const cylinderMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial);\n cylinder.userData = {\n type: 'component',\n componentId: component.id,\n };\n cylinder.rotateX(Math.PI / 2);\n group.add(cylinder);\n\n // Cathode (positive pin) group\n const cathodeGroup = this.createPinGroup(\n component.id,\n component.pins[0]!,\n 'cathode',\n ENodeSourceType.Voltage\n );\n cathodeGroup.position.set(0, 0, -1);\n cathodeGroup.rotateX(-Math.PI / 2);\n group.add(cathodeGroup);\n\n // Anode (negative pin) group\n const anodeGroup = this.createPinGroup(\n component.id,\n component.pins[1]!,\n 'anode',\n ENodeSourceType.Current\n );\n anodeGroup.position.set(0, 0, 1);\n anodeGroup.rotateX(Math.PI / 2);\n group.add(anodeGroup);\n\n return group;\n }\n\n // Uses default hover implementation\n // No animation (battery is static)\n}\n","/**\n * Label Visual Factory\n * @module scene/shared/components/LabelVisualFactory\n *\n * Provides visual factory for Label components - decorative text elements\n * with no electrical connections. Uses CanvasTexture for crisp text rendering.\n */\n\nimport { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { BoxGeometry } from 'three';\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Visual factory for Label components\n *\n * Creates:\n * - Text mesh using CanvasTexture for stencil/technical font styling\n * - Component hitbox for raycasting\n * - No pin groups (Label has zero pins)\n *\n * Configuration:\n * - text: Display text content (max 64 characters, default \"Label\")\n * - size: Scale multiplier (1-10, default 1)\n *\n * @example\n * ```typescript\n * const factory = new LabelVisualFactory();\n * const visual = factory.createVisual(labelComponent);\n * scene.add(visual);\n *\n * // Update text\n * const newConfig = new Map([['text', 'Power Supply'], ['size', '2']]);\n * factory.updateFromConfiguration(visual, newConfig);\n * ```\n */\nexport class LabelVisualFactory extends ComponentVisualFactoryBase {\n /** Maximum text length in characters */\n private static readonly MAX_TEXT_LENGTH = 64;\n\n /** Font family for technical/stencil aesthetic */\n private static readonly FONT_FAMILY = '\"Courier New\", Courier, \"Liberation Mono\", monospace';\n\n /** Text color (dark gray for readability) */\n private static readonly TEXT_COLOR = '#333333';\n\n /** Hover text color (blue tint matching other components) */\n private static readonly HOVER_COLOR = '#4488ff';\n\n /** Selection text color (orange tint matching other components) */\n private static readonly SELECTION_COLOR = '#ff8800';\n\n /** Base font size in pixels */\n private static readonly BASE_FONT_SIZE = 32;\n\n /** Padding around text in pixels */\n private static readonly PADDING = 8;\n\n /**\n * Create the Three.js visual representation for a Label component\n *\n * @param component - The Label component to visualize\n * @returns THREE.Group containing hitbox and text mesh\n */\n createVisual(component: Component): THREE.Object3D {\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Get initial text from config\n const text = component.config.get('text') || 'Label';\n\n // Create text mesh first to get dimensions for hitbox\n const textMesh = this.createTextMesh(text);\n // Preserve canvas/texture refs from createTextMesh, add component metadata\n textMesh.userData.type = 'component';\n textMesh.userData.componentId = component.id;\n textMesh.userData.part = 'text';\n group.add(textMesh);\n\n // Create hitbox based on text mesh dimensions\n const textGeometry = textMesh.geometry as THREE.PlaneGeometry;\n const width = textGeometry.parameters.width;\n const height = textGeometry.parameters.height;\n const hitbox = this.createComponentHitbox(component.id, group.id, width, height, 0.2);\n hitbox.userData.componentType = component.type;\n group.add(hitbox);\n\n // Apply initial configuration (size scaling)\n this.updateFromConfiguration(group, component.config);\n\n return group;\n }\n\n /**\n * Create a canvas with rendered text\n *\n * @param text - Text to render (truncated to MAX_TEXT_LENGTH)\n * @returns HTMLCanvasElement with rendered text\n */\n private createTextCanvas(text: string): HTMLCanvasElement {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d')!;\n\n // Handle device pixel ratio for sharp rendering\n const pixelRatio = Math.min(window.devicePixelRatio || 1, 2);\n const scaledFontSize = LabelVisualFactory.BASE_FONT_SIZE * pixelRatio;\n const scaledPadding = LabelVisualFactory.PADDING * pixelRatio;\n\n // Truncate text to max length\n const displayText = text.slice(0, LabelVisualFactory.MAX_TEXT_LENGTH) || 'Label';\n\n // Set font to measure text\n ctx.font = `bold ${scaledFontSize}px ${LabelVisualFactory.FONT_FAMILY}`;\n const metrics = ctx.measureText(displayText);\n\n // Calculate canvas dimensions\n const textWidth = Math.ceil(metrics.width);\n const textHeight = Math.ceil(scaledFontSize * 1.2); // Add line height factor\n\n canvas.width = textWidth + scaledPadding * 2;\n canvas.height = textHeight + scaledPadding * 2;\n\n // Re-apply font after resize (canvas resize clears context state)\n ctx.font = `bold ${scaledFontSize}px ${LabelVisualFactory.FONT_FAMILY}`;\n ctx.fillStyle = LabelVisualFactory.TEXT_COLOR;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Draw text centered\n ctx.fillText(displayText, canvas.width / 2, canvas.height / 2);\n\n return canvas;\n }\n\n /**\n * Create a text mesh using CanvasTexture\n *\n * @param text - Text to display\n * @returns THREE.Mesh with text texture\n */\n private createTextMesh(text: string): THREE.Mesh {\n const displayText = this.normalizeDisplayText(text);\n\n const canvas = this.createTextCanvas(displayText);\n const texture = new THREE.CanvasTexture(canvas);\n texture.minFilter = THREE.LinearFilter;\n texture.magFilter = THREE.LinearFilter;\n\n const material = new THREE.MeshBasicMaterial({\n map: texture,\n transparent: true,\n side: THREE.DoubleSide,\n depthWrite: false,\n });\n\n // Calculate world-space dimensions\n const pixelRatio = Math.min(window.devicePixelRatio || 1, 2);\n const worldWidth = canvas.width / pixelRatio / 50; // Scale factor for scene units\n const worldHeight = canvas.height / pixelRatio / 50;\n\n const geometry = new THREE.PlaneGeometry(worldWidth, worldHeight);\n const mesh = new THREE.Mesh(geometry, material);\n\n // Store canvas and texture references for updates\n mesh.userData.canvas = canvas;\n mesh.userData.texture = texture;\n mesh.userData.text = displayText;\n\n // Position slightly above ground plane\n mesh.position.set(0, 0.01, 0);\n mesh.rotation.x = -Math.PI / 2; // Lay flat on XZ plane\n\n return mesh;\n }\n\n /**\n * Find the text mesh within the component group\n *\n * @param object3D - The component group\n * @returns The text mesh or null if not found\n */\n private findTextMesh(object3D: THREE.Object3D): THREE.Mesh | null {\n let textMesh: THREE.Mesh | null = null;\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'text') {\n textMesh = child;\n }\n });\n return textMesh;\n }\n\n /**\n * Normalize display text by truncating and providing default\n * @param text\n * @private\n */\n private normalizeDisplayText(text: string): string {\n const displayText = text.slice(0, LabelVisualFactory.MAX_TEXT_LENGTH) || 'Label';\n return displayText;\n }\n\n /**\n * Update the text mesh with new text content\n *\n * Resizes canvas and geometry to fit the new text, then redraws.\n *\n * @param mesh - The text mesh to update\n * @param text - New text content\n * @param group - The parent group containing the hitbox to update\n */\n private updateTextMesh(mesh: THREE.Mesh, text: string, group: THREE.Object3D): void {\n const displayText = this.normalizeDisplayText(text);\n if (displayText === mesh.userData.text) return;\n\n mesh.geometry.dispose();\n\n const canvas = this.createTextCanvas(displayText);\n const texture = new THREE.CanvasTexture(canvas);\n texture.minFilter = THREE.LinearFilter;\n texture.magFilter = THREE.LinearFilter;\n\n const material = new THREE.MeshBasicMaterial({\n map: texture,\n transparent: true,\n side: THREE.DoubleSide,\n depthWrite: false,\n });\n\n // Calculate world-space dimensions\n const pixelRatio = Math.min(window.devicePixelRatio || 1, 2);\n const worldWidth = canvas.width / pixelRatio / 50; // Scale factor for scene units\n const worldHeight = canvas.height / pixelRatio / 50;\n\n mesh.geometry = new THREE.PlaneGeometry(worldWidth, worldHeight);\n mesh.material = material;\n\n // Update hitbox size\n const hitbox = this.findHitbox(group);\n if (hitbox) {\n hitbox.geometry.dispose();\n hitbox.geometry = new BoxGeometry(worldWidth, 0.1, worldHeight);\n }\n\n // Store canvas and texture references for updates\n mesh.userData.canvas = canvas;\n mesh.userData.texture = texture;\n mesh.userData.text = displayText;\n }\n\n /**\n * Update visual based on Label configuration\n *\n * @param object3D - The component group\n * @param config - Configuration map with text and size\n */\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>): void {\n // Update text\n const textMesh = this.findTextMesh(object3D);\n if (textMesh) {\n const newText = config.get('text') || 'Label';\n if (textMesh.userData.text !== newText) {\n this.updateTextMesh(textMesh, newText, object3D);\n }\n }\n\n // Update scale\n const size = parseFloat(config.get('size') || '1');\n const clampedSize = Math.max(1, size);\n object3D.scale.set(clampedSize, clampedSize, clampedSize);\n }\n\n /**\n * Get config form definition for Label component\n *\n * @returns Form definition with text and size fields\n */\n override getConfigFormDefinition(): ConfigFormDefinition {\n return {\n fields: [\n {\n key: 'text',\n label: 'Label Text',\n type: 'text',\n },\n {\n key: 'size',\n label: 'Size',\n type: 'number',\n min: 1,\n max: 16,\n step: 1,\n },\n ],\n };\n }\n\n /**\n * Map core config to form data\n *\n * @param config - Core config from Component.config\n * @returns Form data with appropriate types\n */\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n formData.set('text', config.get('text') || 'Label');\n formData.set('size', parseFloat(config.get('size') || '1'));\n return formData;\n }\n\n /**\n * Map form data back to core config\n *\n * @param formData - Form data from UI\n * @returns Core config with string values\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n\n // Handle text with truncation and default fallback\n let text = String(formData.get('text') || 'Label');\n text = text.slice(0, LabelVisualFactory.MAX_TEXT_LENGTH);\n if (!text.trim()) {\n text = 'Label';\n }\n config.set('text', text);\n\n // Handle size\n const size = Math.max(1, Number(formData.get('size')) || 1);\n config.set('size', String(size));\n\n return config;\n }\n\n /**\n * Apply hover visual effect to the Label\n *\n * Changes text color to hover color (blue) by redrawing the canvas.\n *\n * @param object3D - The component group\n */\n override applyHover(object3D: THREE.Object3D): void {\n object3D.userData.isHovered = true;\n // Selection takes precedence over hover\n if (object3D.userData.isSelected) return;\n this.redrawTextWithColor(object3D, LabelVisualFactory.HOVER_COLOR);\n }\n\n /**\n * Remove hover visual effect from the Label\n *\n * Restores text color to default by redrawing the canvas.\n *\n * @param object3D - The component group\n */\n override removeHover(object3D: THREE.Object3D): void {\n object3D.userData.isHovered = false;\n // Keep selection color if selected\n if (object3D.userData.isSelected) return;\n this.redrawTextWithColor(object3D, LabelVisualFactory.TEXT_COLOR);\n }\n\n /**\n * Apply selection visual effect to the Label\n *\n * Changes text color to selection color (orange) by redrawing the canvas.\n *\n * @param object3D - The component group\n */\n override applySelection(object3D: THREE.Object3D): void {\n object3D.userData.isSelected = true;\n this.redrawTextWithColor(object3D, LabelVisualFactory.SELECTION_COLOR);\n }\n\n /**\n * Remove selection visual effect from the Label\n *\n * Restores text color based on hover state.\n *\n * @param object3D - The component group\n */\n override removeSelection(object3D: THREE.Object3D): void {\n object3D.userData.isSelected = false;\n\n if (object3D.userData.isHovered) {\n this.redrawTextWithColor(object3D, LabelVisualFactory.HOVER_COLOR);\n } else {\n this.redrawTextWithColor(object3D, LabelVisualFactory.TEXT_COLOR);\n }\n }\n\n /**\n * Redraw the text canvas with a specific color\n *\n * @param object3D - The component group\n * @param color - The CSS color string to use\n */\n private redrawTextWithColor(object3D: THREE.Object3D, color: string): void {\n const textMesh = this.findTextMesh(object3D);\n if (!textMesh) {\n return;\n }\n\n const canvas = textMesh.userData.canvas as HTMLCanvasElement;\n const texture = textMesh.userData.texture as THREE.CanvasTexture;\n const displayText = textMesh.userData.text as string;\n\n if (!canvas || !texture || !displayText) {\n return;\n }\n\n const ctx = canvas.getContext('2d')!;\n const pixelRatio = Math.min(window.devicePixelRatio || 1, 2);\n const scaledFontSize = LabelVisualFactory.BASE_FONT_SIZE * pixelRatio;\n\n // Clear and redraw with new color\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.font = `bold ${scaledFontSize}px ${LabelVisualFactory.FONT_FAMILY}`;\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(displayText, canvas.width / 2, canvas.height / 2);\n\n texture.needsUpdate = true;\n }\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component, ComponentState, LightbulbState } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\n\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Visual factory for Lightbulb components\n *\n * Creates:\n * - LED cylinder mesh\n * - Input pin group\n * - Output pin group\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Lightbulb is lit (based on simulation state)\n */\nexport class LightbulbVisualFactory extends ComponentVisualFactoryBase {\n /** Lightbulb lit color (yellow glow) */\n private static readonly BULB_LIT_COLOR = 0xffff00;\n\n /** Lightbulb lit emissive intensity */\n private static readonly BULB_LIT_INTENSITY = 1.0;\n\n createVisual(component: Component): THREE.Object3D {\n // Root group (not rendered, just organizational)\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 1, 4, 1);\n group.add(hitbox);\n\n // Visuals\n const baseMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const baseGeometry = new THREE.CylinderGeometry(0.23, 0.2, 0.5, 16, 4, false, 0, Math.PI * 2);\n const base = new THREE.Mesh(baseGeometry, baseMaterial);\n base.userData = {\n type: 'component',\n componentId: component.id,\n part: 'base',\n };\n base.position.set(0, 0.2, 0);\n group.add(base);\n\n const bulbMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n bulbMaterial.opacity = 0.55;\n const bulbGeometry = new THREE.SphereGeometry(0.5, 12, 8);\n const bulb = new THREE.Mesh(bulbGeometry, bulbMaterial);\n bulb.userData = {\n type: 'component',\n componentId: component.id,\n part: 'bulb',\n };\n bulb.position.set(0, 0.8, 0);\n group.add(bulb);\n\n // pin1 group\n const pin1Group = this.createPinGroup(component.id, component.pins[0]!, 'pin1');\n pin1Group.position.set(-0.25, 0, 0);\n pin1Group.rotateZ(Math.PI / 2);\n pin1Group.rotateY(Math.PI);\n group.add(pin1Group);\n\n // Output pin group\n const pin2Group = this.createPinGroup(component.id, component.pins[1]!, 'pin2');\n pin2Group.position.set(0.25, 0, 0);\n pin2Group.rotateZ(-Math.PI / 2);\n pin2Group.rotateY(Math.PI);\n group.add(pin2Group);\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n /**\n * Get config form definition for Lightbulb\n *\n * @returns Form definition with size\n */\n override getConfigFormDefinition(): ConfigFormDefinition | null {\n return {\n fields: [{ key: 'size', label: 'Size', type: 'number', min: 1, max: 16, step: 1 }],\n };\n }\n\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n formData.set('size', parseFloat(config.get('size') || '1'));\n return formData;\n }\n\n /**\n * Map form data to core config (T024)\n * Converts boolean to \"open\"/\"closed\" strings\n *\n * @param formData - Form data with boolean initialState\n * @returns Core config with string initialState\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n config.set('size', formData.get('size').toString());\n return config;\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const scale = parseFloat(config.get('size') || '1');\n object3D.scale.set(scale, scale, scale);\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update Lightbulb animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The SmallLED's current simulation state\n *\n * @remarks\n * Applies yellow emissive glow when Lightbulb is lit (state.isLit === true)\n */\n override updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void {\n const bulbMesh = this.findBulbMesh(object3D);\n if (!bulbMesh) return;\n if (!state) {\n bulbMesh.userData.materialLocked = false;\n bulbMesh.material.opacity = 0.55;\n bulbMesh.material.emissive.setHex(0x000000);\n bulbMesh.material.emissiveIntensity = 0;\n return;\n }\n\n const lightbulbState = state as LightbulbState;\n if (lightbulbState.isLit) {\n // Apply LED glow\n bulbMesh.userData.materialLocked = true;\n bulbMesh.material.opacity = 1;\n bulbMesh.material.emissive.setHex(LightbulbVisualFactory.BULB_LIT_COLOR);\n bulbMesh.material.emissiveIntensity = LightbulbVisualFactory.BULB_LIT_INTENSITY;\n } else {\n // Remove glow\n bulbMesh.userData.materialLocked = false;\n bulbMesh.material.opacity = 0.55;\n bulbMesh.material.emissive.setHex(0x000000);\n bulbMesh.material.emissiveIntensity = 0;\n }\n }\n\n /**\n * Find the bulb mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The LED mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'bulb'\n */\n private findBulbMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let bulbMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'bulb') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n bulbMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n\n return bulbMesh;\n }\n\n // Uses default hover implementation\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component, ComponentState, SmallLEDState } from 'simple-circuit-engine/core';\nimport { presetOrHexToHex, hexToPresetOrHex } from '../utils/ColorUtils';\nimport * as THREE from 'three';\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Visual factory for SmallLED components\n *\n * Creates:\n * - LED box mesh\n * - Input pin group\n * - Output pin group\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when LED is lit (based on simulation state)\n */\nexport class RectangleLEDVisualFactory extends ComponentVisualFactoryBase {\n /** LED lit color (yellow glow) */\n private static readonly LED_LIT_COLOR = 0xffff00;\n\n /** LED lit emissive intensity */\n private static readonly LED_LIT_INTENSITY = 1.0;\n\n createVisual(component: Component): THREE.Object3D {\n // Root group (not rendered, just organizational)\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 1, 1.5, 1);\n group.add(hitbox);\n\n // Visual LED\n const ledMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const ledGeometry = new THREE.BoxGeometry(1, 1, 1);\n const led = new THREE.Mesh(ledGeometry, ledMaterial);\n led.userData = {\n type: 'component',\n componentId: component.id,\n part: 'led',\n idleColorHex: 0xffffff,\n activeColorHex: RectangleLEDVisualFactory.LED_LIT_COLOR,\n };\n led.position.set(0, 0.25, 0);\n group.add(led);\n\n // Input pin group\n const inputPinGroup = this.createPinGroup(component.id, component.pins[0]!, 'input');\n inputPinGroup.position.set(-0.5, 0, 0);\n inputPinGroup.rotateZ(Math.PI / 2);\n inputPinGroup.rotateY(Math.PI);\n group.add(inputPinGroup);\n\n // Output pin group\n const outputPinGroup = this.createPinGroup(component.id, component.pins[1]!, 'output');\n outputPinGroup.position.set(0.5, 0, 0);\n outputPinGroup.rotateZ(-Math.PI / 2);\n outputPinGroup.rotateY(Math.PI);\n group.add(outputPinGroup);\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n /**\n * Get config form definition for SmallLED (T027)\n *\n * @returns Form definition with activeColor and idleColor color fields\n */\n override getConfigFormDefinition(): ConfigFormDefinition | null {\n return {\n fields: [\n { key: 'idleColor', label: 'Idle Color', type: 'color' },\n { key: 'activeColor', label: 'Active Color', type: 'color' },\n { key: 'size', label: 'Size', type: 'number', min: 1, max: 16, step: 1 },\n { key: 'hwRatio', label: 'Ratio H/W', type: 'number' },\n { key: 'ywRatio', label: 'Ratio Y/W', type: 'number' },\n ],\n };\n }\n\n /**\n * Map core config to form data (T027)\n * Converts hex/preset strings to hex values for color picker\n *\n * @param config - Core component config\n * @returns Form data with hex color strings\n */\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n const idleColor = config.get('idleColor') || '#ffffff';\n const activeColor = config.get('activeColor') || '#ffff00';\n\n // Convert preset names to hex if needed\n formData.set('idleColor', presetOrHexToHex(idleColor));\n formData.set('activeColor', presetOrHexToHex(activeColor));\n formData.set('size', parseFloat(config.get('size') || '1'));\n formData.set('hwRatio', parseFloat(config.get('hwRatio') || '1'));\n formData.set('ywRatio', parseFloat(config.get('ywRatio') || '1'));\n\n return formData;\n }\n\n /**\n * Map form data to core config (T027)\n * Converts hex colors to preset names if they match, otherwise keeps hex\n *\n * @param formData - Form data with hex color strings\n * @returns Core config with hex or preset name strings\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n const activeColor = formData.get('activeColor');\n const idleColor = formData.get('idleColor');\n\n // Convert hex to preset name if it matches a preset\n if (activeColor) {\n config.set('activeColor', hexToPresetOrHex(activeColor));\n }\n if (idleColor) {\n config.set('idleColor', hexToPresetOrHex(idleColor));\n }\n\n config.set('size', formData.get('size').toString());\n config.set('hwRatio', formData.get('hwRatio').toString());\n config.set('ywRatio', formData.get('ywRatio').toString());\n return config;\n }\n\n /**\n * Update visual from configuration (T022)\n * Updates LED color based on activeColor config\n *\n * @param object3D - The Object3D created by createVisual()\n * @param config - Component configuration map\n *\n * @remarks\n * Updates the LED mesh color based on activeColor config value\n * Supports both hex colors and color presets\n */\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>): void {\n const ledMesh = this.findLedMesh(object3D);\n const inputPin = this.findPinGroup(object3D, 'input');\n const outputPin = this.findPinGroup(object3D, 'output');\n const hitbox = this.findHitbox(object3D);\n if (!ledMesh || !inputPin || !outputPin || !hitbox) return;\n\n // changing colors\n const idleColor = config.get('idleColor');\n if (idleColor) {\n // Convert preset to hex if needed, then parse\n const idleColorHex = parseInt(presetOrHexToHex(idleColor).replace('#', ''), 16);\n ledMesh.material.color.setHex(idleColorHex);\n ledMesh.userData.idleColorHex = idleColorHex;\n }\n const activeColor = config.get('activeColor');\n if (activeColor) {\n // Convert preset to hex if needed, then parse\n ledMesh.userData.activeColorHex = parseInt(\n presetOrHexToHex(activeColor).replace('#', ''),\n 16\n );\n }\n // changing geometry\n const hwRatio = parseFloat(config.get('hwRatio') || '1');\n const ywRatio = parseFloat(config.get('ywRatio') || '1');\n ledMesh.geometry.dispose();\n ledMesh.geometry = new THREE.BoxGeometry(1, ywRatio, hwRatio);\n ledMesh.position.set(0, 0.25 * ywRatio, 0);\n hitbox.geometry.dispose();\n hitbox.geometry = new THREE.BoxGeometry(1, 1.5 * ywRatio, hwRatio);\n // scaling the pins (1 if hwRatio>=0.5, else scaled down to fit better)\n const pinScale = hwRatio >= 0.5 ? 1 : hwRatio * 2;\n inputPin.scale.set(pinScale, pinScale, pinScale);\n outputPin.scale.set(pinScale, pinScale, pinScale);\n\n // scaling\n const scale = parseFloat(config.get('size') || '1');\n object3D.scale.set(scale, scale, scale);\n }\n\n /**\n * Update LED animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The SmallLED's current simulation state\n *\n * @remarks\n * Applies yellow emissive glow when LED is lit (state.isLit === true)\n */\n override updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void {\n const ledMesh = this.findLedMesh(object3D);\n if (!ledMesh) return;\n if (!state) {\n ledMesh.userData.materialLocked = false;\n ledMesh.material.emissive.setHex(0x000000);\n ledMesh.material.emissiveIntensity = 0;\n return;\n }\n\n const ledState = state as SmallLEDState;\n if (ledState.isLit) {\n // Apply LED glow\n ledMesh.userData.materialLocked = true;\n ledMesh.material.emissive.setHex(ledMesh.userData.activeColorHex);\n ledMesh.material.emissiveIntensity = RectangleLEDVisualFactory.LED_LIT_INTENSITY;\n } else {\n // Remove glow\n ledMesh.userData.materialLocked = false;\n ledMesh.material.emissive.setHex(0x000000);\n ledMesh.material.emissiveIntensity = 0;\n }\n }\n\n /**\n * Find the LED mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The LED mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'led'\n */\n private findLedMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let ledMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'led') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n ledMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n\n return ledMesh;\n }\n\n // Uses default hover implementation\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component, ComponentState, RelayState } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Visual factory for Relay components\n *\n * Creates:\n * - Component hitbox for raycasting\n * - Cylinder representing the coil with two poles\n * - Output commanded switch with contactor\n * - Contactor (cylinder, rotatable for animation)\n * Animation:\n * - Rotates contactor based on open/closed state\n */\nexport class RelayVisualFactory extends ComponentVisualFactoryBase {\n /** Rotation for open relay (contactor misaligned) */\n private static readonly OPEN_ROTATION = new THREE.Euler(0.2, (-0.6 * Math.PI) / 2, 0.2);\n /** Rotation for opening/closing relay */\n private static readonly INTERMEDIATE_ROTATION = new THREE.Euler(0.1, (-0.8 * Math.PI) / 2, 0.1);\n /** Rotation for closed relay (contactor aligned) */\n private static readonly CLOSED_ROTATION = new THREE.Euler(0, -Math.PI / 2, 0);\n /** Rotation for opening/closing negative activation logic relay */\n private static readonly INVERTED_INTERMEDIATE_ROTATION = new THREE.Euler(\n -0.1,\n (-1.2 * Math.PI) / 2,\n -0.1\n );\n /** Rotation for open negative activation logic relay (contactor misaligned toward the coil) */\n private static readonly INVERTED_OPEN_ROTATION = new THREE.Euler(\n -0.2,\n (-1.4 * Math.PI) / 2,\n -0.2\n );\n\n createVisual(component: Component): THREE.Object3D {\n // Root group (not rendered, just organizational)\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 2, 1, 2);\n group.add(hitbox);\n\n // Visual: input parts\n const coilGeometry = new THREE.CylinderGeometry(0.4, 0.4, 1.2, 24);\n const coilMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const coil = new THREE.Mesh(coilGeometry, coilMaterial);\n coil.userData = {\n type: 'component',\n componentId: component.id,\n part: 'coil',\n };\n coil.rotateX(Math.PI / 2);\n coil.position.set(-0.7, 0, 0);\n group.add(coil);\n\n // cmd in pin\n const cmdInGroup = this.createPinGroup(component.id, component.pins[0]!, 'cmd_in');\n cmdInGroup.position.set(-0.8, 0, -0.6);\n cmdInGroup.rotateX(-Math.PI / 2);\n // addition to group after to avoid z-fighting\n\n // cmd out pin\n const cmdOutGroup = this.createPinGroup(component.id, component.pins[1]!, 'cmd_out');\n cmdOutGroup.position.set(-0.8, 0, 0.6);\n cmdOutGroup.rotateX(Math.PI / 2);\n group.add(cmdOutGroup);\n\n // Visual: output parts\n const powerInGeometry = new THREE.SphereGeometry(0.3, 16, 8, Math.PI / 2, Math.PI, 0, Math.PI);\n const powerMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const powerInPole = new THREE.Mesh(powerInGeometry, powerMaterial);\n powerInPole.userData = {\n type: 'component',\n componentId: component.id,\n };\n powerInPole.rotateY(-Math.PI / 2);\n powerInPole.position.set(0.6, 0, -0.5);\n group.add(powerInPole);\n\n // power in pin\n const powerInGroup = this.createPinGroup(component.id, component.pins[2]!, 'power_in');\n powerInGroup.position.set(0.6, 0, -0.5);\n powerInGroup.rotateZ(Math.PI / 2);\n powerInGroup.rotateX(-Math.PI / 2);\n // to avoid z-fighting\n powerInGroup.renderOrder = 1;\n powerInGroup.children.forEach((child) => {\n child.renderOrder = 1;\n });\n group.add(powerInGroup);\n group.add(cmdInGroup);\n\n const powerOutGeometry = new THREE.BoxGeometry(0.2, 0.3, 1);\n const powerOutPole = new THREE.Mesh(powerOutGeometry, powerMaterial);\n powerOutPole.userData = {\n type: 'component',\n componentId: component.id,\n };\n powerOutPole.rotateY(Math.PI / 2);\n powerOutPole.position.set(0.5, 0, 0.9);\n group.add(powerOutPole);\n\n // power out pin\n const powerOutGroup = this.createPinGroup(component.id, component.pins[3]!, 'power_out');\n powerOutGroup.position.set(0.6, 0, 1);\n powerOutGroup.rotateZ(-Math.PI / 2);\n powerOutGroup.rotateX(Math.PI / 2);\n group.add(powerOutGroup);\n\n // Contactor\n const contactorGroup = new THREE.Mesh(\n new THREE.BoxGeometry(2, 1, 1),\n //new THREE.MeshStandardMaterial({ color: 0x00ff00, transparent: true, opacity: 0.2 })\n new THREE.MeshBasicMaterial({\n transparent: false,\n visible: false,\n })\n );\n contactorGroup.userData = {\n type: 'component',\n componentId: component.id,\n part: 'contactor',\n initialState: 'open',\n };\n\n const contactorMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const contactorGeometry = new THREE.CylinderGeometry(\n 0.2,\n 0.12,\n 1.3,\n 8,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n const contactor = new THREE.Mesh(contactorGeometry, contactorMaterial);\n contactor.rotateX(-Math.PI / 2);\n contactor.rotateZ(Math.PI / 2);\n contactor.position.set(0.75, 0, 0);\n contactorGroup.add(contactor);\n\n group.add(contactorGroup);\n contactorGroup.position.set(0.6, 0, -0.6);\n contactorGroup.rotation.copy(RelayVisualFactory.OPEN_ROTATION);\n\n // take config into account\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n /**\n * Get config form definition for Relay (T025)\n *\n * @returns Form definition with activationLogic boolean field\n */\n override getConfigFormDefinition(): ConfigFormDefinition | null {\n return {\n fields: [\n {\n key: 'activationLogic',\n label: 'Activation Logic',\n type: 'boolean',\n },\n {\n key: 'transitionSpan',\n label: 'Transition Span (ticks)',\n type: 'number',\n },\n {\n key: 'size',\n label: 'Size',\n type: 'number',\n min: 1,\n max: 16,\n step: 1,\n },\n {\n key: 'initializationOrder',\n label: 'Init Order',\n type: 'number',\n },\n ],\n };\n }\n\n /**\n * Map core config to form data (T025)\n * Converts \"positive\"/\"negative\" strings to boolean\n *\n * @param config - Core component config\n * @returns Form data with boolean activationLogic\n */\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n const activationLogic = config.get('activationLogic');\n formData.set('activationLogic', activationLogic === 'positive');\n formData.set('transitionSpan', parseFloat(config.get('transitionSpan') || '1'));\n formData.set('size', parseFloat(config.get('size') || '1'));\n formData.set('initializationOrder', parseFloat(config.get('initializationOrder') || '0'));\n return formData;\n }\n\n /**\n * Map form data to core config (T025)\n * Converts boolean to \"positive\"/\"negative\" strings\n *\n * @param formData - Form data with boolean activationLogic\n * @returns Core config with string activationLogic\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n const activationLogic = formData.get('activationLogic');\n config.set('activationLogic', activationLogic ? 'positive' : 'negative');\n config.set('transitionSpan', formData.get('transitionSpan').toString());\n config.set('size', formData.get('size').toString());\n config.set('initializationOrder', formData.get('initializationOrder').toString() || null);\n return config;\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const contactorGroup = this.findContactorGroup(object3D);\n if (contactorGroup) {\n if (config.get('activationLogic') === 'negative') {\n contactorGroup.userData.initialState = 'closed';\n } else {\n contactorGroup.userData.initialState = 'open';\n }\n }\n const scale = parseFloat(config.get('size') || '1');\n object3D.scale.set(scale, scale, scale);\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update relay animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The Relay's current simulation state\n *\n * @remarks\n * Rotates the contactor group to visually represent open/closed state\n */\n override updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void {\n const contactorGroup = this.findContactorGroup(object3D);\n const coil = this.findCoil(object3D);\n\n if (!state) {\n // Edition mode - set to initial state\n if (contactorGroup) {\n if (contactorGroup.userData.initialState === 'closed') {\n contactorGroup.rotation.copy(RelayVisualFactory.CLOSED_ROTATION);\n } else {\n contactorGroup.rotation.copy(RelayVisualFactory.OPEN_ROTATION);\n }\n }\n if (coil && coil.material instanceof THREE.MeshStandardMaterial) {\n coil.material.emissive.setHex(0x000000);\n coil.material.emissiveIntensity = 0;\n coil.userData.materialLocked = false;\n }\n return;\n }\n\n const relayState = state as RelayState;\n if (contactorGroup) {\n if (relayState.isInTransition) {\n const targetRotation =\n contactorGroup.userData.initialState === 'closed'\n ? RelayVisualFactory.INVERTED_INTERMEDIATE_ROTATION\n : RelayVisualFactory.INTERMEDIATE_ROTATION;\n contactorGroup.rotation.copy(targetRotation);\n } else if (relayState.isClosed) {\n // Closed position - contactor aligned\n contactorGroup.rotation.copy(RelayVisualFactory.CLOSED_ROTATION);\n } else {\n // Open position - contactor misaligned\n const targetRotation =\n contactorGroup.userData.initialState === 'closed'\n ? RelayVisualFactory.INVERTED_OPEN_ROTATION\n : RelayVisualFactory.OPEN_ROTATION;\n contactorGroup.rotation.copy(targetRotation);\n }\n }\n\n if (coil && coil.material instanceof THREE.MeshStandardMaterial) {\n if (relayState.isInTransition) {\n coil.material.emissive.setHex(0xff00ff);\n coil.material.emissiveIntensity = 0.6;\n coil.userData.materialLocked = true;\n } else if (relayState.isClosed) {\n coil.material.emissive.setHex(0xff00ff);\n coil.material.emissiveIntensity = 1;\n coil.userData.materialLocked = true;\n } else {\n coil.material.emissive.setHex(0x000000);\n coil.material.emissiveIntensity = 0;\n coil.userData.materialLocked = false;\n }\n }\n }\n\n /**\n * Find the contactor group within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The contactor's parent group if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'contactor' and returns its parent\n */\n private findContactorGroup(object3D: THREE.Object3D): THREE.Object3D | null {\n let contactorGroup: THREE.Object3D | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'contactor') {\n contactorGroup = child;\n }\n });\n\n return contactorGroup;\n }\n\n /**\n * Find the coil within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The contactor's parent group if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'coil' and returns its parent\n */\n private findCoil(object3D: THREE.Object3D): THREE.Mesh | null {\n let coil: THREE.Object3D | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'coil') {\n coil = child;\n }\n });\n return coil;\n }\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component, ComponentState, SmallLEDState } from 'simple-circuit-engine/core';\nimport { presetOrHexToHex, hexToPresetOrHex } from '../utils/ColorUtils';\nimport * as THREE from 'three';\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Visual factory for SmallLED components\n *\n * Creates:\n * - LED cylinder mesh\n * - Input pin group\n * - Output pin group\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when LED is lit (based on simulation state)\n */\nexport class SmallLEDVisualFactory extends ComponentVisualFactoryBase {\n /** LED lit color (yellow glow) */\n private static readonly LED_LIT_COLOR = 0xffff00;\n\n /** LED lit emissive intensity */\n private static readonly LED_LIT_INTENSITY = 1.0;\n\n createVisual(component: Component): THREE.Object3D {\n // Root group (not rendered, just organizational)\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 1, 1, 1);\n group.add(hitbox);\n\n // Visual LED\n const ledMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const ledGeometry = new THREE.CylinderGeometry(0.25, 0.25, 1, 16, 4, false, 0, Math.PI * 2);\n const led = new THREE.Mesh(ledGeometry, ledMaterial);\n led.userData = {\n type: 'component',\n componentId: component.id,\n part: 'led',\n idleColorHex: 0xffffff,\n activeColorHex: SmallLEDVisualFactory.LED_LIT_COLOR,\n };\n led.position.set(0, 0.25, 0);\n group.add(led);\n\n // Input pin group\n const inputPinGroup = this.createPinGroup(component.id, component.pins[0]!, 'input');\n inputPinGroup.position.set(-0.25, 0, 0);\n inputPinGroup.rotateZ(Math.PI / 2);\n inputPinGroup.rotateY(Math.PI);\n group.add(inputPinGroup);\n\n // Output pin group\n const outputPinGroup = this.createPinGroup(component.id, component.pins[1]!, 'output');\n outputPinGroup.position.set(0.25, 0, 0);\n outputPinGroup.rotateZ(-Math.PI / 2);\n outputPinGroup.rotateY(Math.PI);\n group.add(outputPinGroup);\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n /**\n * Get config form definition for SmallLED (T027)\n *\n * @returns Form definition with activeColor and idleColor color fields\n */\n override getConfigFormDefinition(): ConfigFormDefinition | null {\n return {\n fields: [\n { key: 'idleColor', label: 'Idle Color', type: 'color' },\n { key: 'activeColor', label: 'Active Color', type: 'color' },\n { key: 'size', label: 'Size', type: 'number', min: 1, max: 16, step: 1 },\n { key: 'ywRatio', label: 'Ratio Y/W', type: 'number' },\n ],\n };\n }\n\n /**\n * Map core config to form data (T027)\n * Converts hex/preset strings to hex values for color picker\n *\n * @param config - Core component config\n * @returns Form data with hex color strings\n */\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n const activeColor = config.get('activeColor') || '#ffff00';\n const idleColor = config.get('idleColor') || '#ffffff';\n\n // Convert preset names to hex if needed\n formData.set('idleColor', presetOrHexToHex(idleColor));\n formData.set('activeColor', presetOrHexToHex(activeColor));\n formData.set('size', parseFloat(config.get('size') || '1'));\n formData.set('ywRatio', parseFloat(config.get('ywRatio') || '1'));\n\n return formData;\n }\n\n /**\n * Map form data to core config (T027)\n * Converts hex colors to preset names if they match, otherwise keeps hex\n *\n * @param formData - Form data with hex color strings\n * @returns Core config with hex or preset name strings\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n const activeColor = formData.get('activeColor');\n const idleColor = formData.get('idleColor');\n\n // Convert hex to preset name if it matches a preset\n if (activeColor) {\n config.set('activeColor', hexToPresetOrHex(activeColor));\n }\n if (idleColor) {\n config.set('idleColor', hexToPresetOrHex(idleColor));\n }\n\n config.set('size', formData.get('size').toString());\n config.set('ywRatio', formData.get('ywRatio').toString());\n return config;\n }\n\n /**\n * Update visual from configuration (T022)\n * Updates LED color based on activeColor config\n *\n * @param object3D - The Object3D created by createVisual()\n * @param config - Component configuration map\n *\n * @remarks\n * Updates the LED mesh color based on activeColor config value\n * Supports both hex colors and color presets\n */\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>): void {\n const ledMesh = this.findLedMesh(object3D);\n const hitbox = this.findHitbox(object3D);\n if (!ledMesh || !hitbox) return;\n\n // changing colors\n const idleColor = config.get('idleColor');\n if (idleColor) {\n // Convert preset to hex if needed, then parse\n const idleColorHex = parseInt(presetOrHexToHex(idleColor).replace('#', ''), 16);\n ledMesh.material.color.setHex(idleColorHex);\n ledMesh.userData.idleColorHex = idleColorHex;\n }\n const activeColor = config.get('activeColor');\n if (activeColor) {\n // Convert preset to hex if needed, then parse\n ledMesh.userData.activeColorHex = parseInt(\n presetOrHexToHex(activeColor).replace('#', ''),\n 16\n );\n }\n // changing geometry\n const ywRatio = parseFloat(config.get('ywRatio') || '1');\n ledMesh.geometry.dispose();\n ledMesh.geometry = new THREE.CylinderGeometry(\n 0.25,\n 0.25,\n ywRatio,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n ledMesh.position.set(0, 0.25 * ywRatio, 0);\n hitbox.geometry.dispose();\n hitbox.geometry = new THREE.BoxGeometry(1, 1.5 * ywRatio, 1);\n\n const scale = parseFloat(config.get('size') || '1');\n object3D.scale.set(scale, scale, scale);\n }\n\n /**\n * Update LED animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The SmallLED's current simulation state\n *\n * @remarks\n * Applies yellow emissive glow when LED is lit (state.isLit === true)\n */\n override updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void {\n const ledMesh = this.findLedMesh(object3D);\n if (!ledMesh) return;\n if (!state) {\n ledMesh.userData.materialLocked = false;\n ledMesh.material.emissive.setHex(0x000000);\n ledMesh.material.emissiveIntensity = 0;\n return;\n }\n\n const ledState = state as SmallLEDState;\n if (ledState.isLit) {\n // Apply LED glow\n ledMesh.userData.materialLocked = true;\n ledMesh.material.emissive.setHex(ledMesh.userData.activeColorHex);\n ledMesh.material.emissiveIntensity = SmallLEDVisualFactory.LED_LIT_INTENSITY;\n } else {\n // Remove glow\n ledMesh.userData.materialLocked = false;\n ledMesh.material.emissive.setHex(0x000000);\n ledMesh.material.emissiveIntensity = 0;\n }\n }\n\n /**\n * Find the LED mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The LED mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'led'\n */\n private findLedMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let ledMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'led') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n ledMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n\n return ledMesh;\n }\n\n // Uses default hover implementation\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component, ComponentState, SwitchState } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Visual factory for Switch components\n *\n * Creates:\n * - Input pole (sphere)\n * - Output pole (box)\n * - Contactor (cylinder, rotatable for animation)\n * - Input pin group\n * - Output pin group\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Rotates contactor based on open/closed state\n */\nexport class SwitchVisualFactory extends ComponentVisualFactoryBase {\n /** Rotation for closed switch (contactor aligned) */\n private static readonly CLOSED_ROTATION = new THREE.Euler(0, 0, 0);\n /** Rotation for opening/closing switch */\n private static readonly INTERMEDIATE_ROTATION = new THREE.Euler(0.25, 0.65, 0.25);\n /** Rotation for open switch (contactor misaligned) */\n private static readonly OPEN_ROTATION = new THREE.Euler(0.5, 1.3, 0.5);\n\n createVisual(component: Component): THREE.Object3D {\n // Root group (not rendered, just organizational)\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 2, 1, 1);\n group.add(hitbox);\n\n // Visual: poles\n const inputPoleGeometry = new THREE.SphereGeometry(\n 0.3,\n 16,\n 8,\n Math.PI / 2,\n Math.PI,\n 0,\n Math.PI\n );\n const poleMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n\n const inputPole = new THREE.Mesh(inputPoleGeometry, poleMaterial);\n inputPole.userData = {\n type: 'component',\n componentId: component.id,\n };\n inputPole.position.set(-1, 0, 0);\n group.add(inputPole);\n\n const outputPoleGeometry = new THREE.BoxGeometry(0.2, 0.3, 1);\n const outputPole = new THREE.Mesh(outputPoleGeometry, poleMaterial);\n outputPole.userData = {\n type: 'component',\n componentId: component.id,\n };\n outputPole.position.set(0.5, 0, 0);\n group.add(outputPole);\n\n // Contactor\n const contactorGroup = new THREE.Mesh(\n new THREE.BoxGeometry(2, 1, 1),\n new THREE.MeshBasicMaterial({\n transparent: false,\n visible: false,\n })\n );\n contactorGroup.userData = {\n type: 'component',\n componentId: component.id,\n part: 'contactor',\n initialState: 'open',\n };\n\n const contactorMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const contactorGeometry = new THREE.CylinderGeometry(\n 0.2,\n 0.12,\n 1.5,\n 8,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n const contactor = new THREE.Mesh(contactorGeometry, contactorMaterial);\n\n contactor.rotateZ(Math.PI / 2);\n contactor.position.set(0.65, 0, 0);\n contactorGroup.add(contactor);\n\n group.add(contactorGroup);\n contactorGroup.position.set(-1, 0, 0);\n contactorGroup.rotation.copy(SwitchVisualFactory.OPEN_ROTATION);\n\n // Input pin group\n const inputPinGroup = this.createPinGroup(component.id, component.pins[0]!, 'input');\n inputPinGroup.position.set(-1, 0, 0);\n inputPinGroup.rotateZ(Math.PI / 2);\n inputPinGroup.rotateY(Math.PI);\n group.add(inputPinGroup);\n\n // Output pin group\n const outputPinGroup = this.createPinGroup(component.id, component.pins[1]!, 'output');\n outputPinGroup.position.set(0.6, 0, 0);\n outputPinGroup.rotateZ(-Math.PI / 2);\n outputPinGroup.rotateY(Math.PI);\n group.add(outputPinGroup);\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n /**\n * Get config form definition for Switch (T024)\n *\n * @returns Form definition with initialState boolean field\n */\n override getConfigFormDefinition(): ConfigFormDefinition | null {\n return {\n fields: [\n {\n key: 'initialState',\n label: 'Open at start',\n type: 'boolean',\n },\n {\n key: 'size',\n label: 'Size',\n type: 'number',\n min: 1,\n max: 16,\n step: 1,\n },\n ],\n };\n }\n\n /**\n * Map core config to form data (T024)\n * Converts \"open\"/\"closed\" strings to boolean\n *\n * @param config - Core component config\n * @returns Form data with boolean initialState\n */\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n const initialState = config.get('initialState');\n formData.set('initialState', initialState === 'open');\n formData.set('size', parseFloat(config.get('size') || '1'));\n return formData;\n }\n\n /**\n * Map form data to core config (T024)\n * Converts boolean to \"open\"/\"closed\" strings\n *\n * @param formData - Form data with boolean initialState\n * @returns Core config with string initialState\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n const initialState = formData.get('initialState');\n config.set('initialState', initialState ? 'open' : 'closed');\n config.set('size', formData.get('size').toString());\n return config;\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const contactorGroup = this.findContactorGroup(object3D);\n if (!contactorGroup) return;\n\n if (config.get('initialState') === 'closed') {\n contactorGroup.userData.initialState = 'closed';\n } else {\n contactorGroup.userData.initialState = 'open';\n }\n\n const scale = parseFloat(config.get('size') || '1');\n object3D.scale.set(scale, scale, scale);\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update switch animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The Switch's current simulation state, or null in edition mode\n *\n * @remarks\n * Rotates the contactor group to visually represent open/closed state\n */\n override updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void {\n const contactorGroup = this.findContactorGroup(object3D);\n if (!contactorGroup) return;\n if (!state) {\n if (contactorGroup.userData.initialState === 'closed') {\n contactorGroup.rotation.copy(SwitchVisualFactory.CLOSED_ROTATION);\n } else {\n contactorGroup.rotation.copy(SwitchVisualFactory.OPEN_ROTATION);\n }\n return;\n }\n\n const switchState = state as SwitchState;\n if (switchState.isInTransition) {\n contactorGroup.rotation.copy(SwitchVisualFactory.INTERMEDIATE_ROTATION);\n } else if (switchState.isClosed) {\n // Closed position - contactor aligned\n contactorGroup.rotation.copy(SwitchVisualFactory.CLOSED_ROTATION);\n } else {\n // Open position - contactor misaligned\n contactorGroup.rotation.copy(SwitchVisualFactory.OPEN_ROTATION);\n }\n }\n\n /**\n * Find the contactor group within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The contactor's parent group if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'contactor' and returns its parent\n */\n private findContactorGroup(object3D: THREE.Object3D): THREE.Object3D | null {\n let contactorGroup: THREE.Object3D | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'contactor') {\n contactorGroup = child;\n }\n });\n\n return contactorGroup;\n }\n\n // Uses default hover implementation\n}\n","import { ComponentVisualFactoryBase } from './ComponentVisualFactory';\nimport type { Component, ComponentState, TransistorState } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { RingGeometry } from '../utils/GeometryUtils';\nimport type {ConfigFormDefinition} from \"../types\";\n\n/**\n * Visual factory for Transistor components\n *\n * Creates:\n * - Transistor Ring mesh\n * - Collector, Base and Emitter pin group\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Transistor is lit (based on simulation state)\n */\nexport class TransistorVisualFactory extends ComponentVisualFactoryBase {\n /** Transistor lit color (yellow glow) */\n private static readonly TRANSISTOR_CLOSED_COLOR = 0xffffff;\n /** Transistor lit emissive intensity */\n private static readonly TRANSISTOR_CLOSED_INTENSITY = 0.3;\n /** Shared open Transistor envelope geometry */\n private readonly openGeometry = RingGeometry(0.4, 0.5, 0.4, 16);\n /** Shared transient Transistor envelope geometry */\n private readonly transientGeometry = RingGeometry(0.2, 0.5, 0.4, 16);\n /** Shared transient Transistor envelope geometry */\n private readonly closedGeometry = RingGeometry(0.01, 0.5, 0.4, 16);\n\n createVisual(component: Component): THREE.Object3D {\n // Root group (not rendered, just organizational)\n const group = new THREE.Group();\n group.userData = {\n type: 'componentGroup',\n componentId: component.id,\n componentType: component.type,\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 1.3, 2, 1.3);\n group.add(hitbox);\n\n // Visual Transistor\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(TransistorVisualFactory.TRANSISTOR_CLOSED_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.openGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'open',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.position.set(0, -0.05, 0);\n group.add(envelope);\n\n // Collector pin group\n const collectorGroup = this.createPinGroup(component.id, component.pins[0]!, 'collector');\n collectorGroup.position.set(0.05, 0, -0.4);\n collectorGroup.rotateX(-Math.PI / 2);\n group.add(collectorGroup);\n\n // Base pin group\n const baseGroup = this.createPinGroup(component.id, component.pins[1]!, 'base');\n baseGroup.position.set(-0.45, 0, 0);\n baseGroup.rotateZ(Math.PI / 2);\n baseGroup.rotateY(Math.PI);\n group.add(baseGroup);\n\n // Emitter pin group\n const emitterGroup = this.createPinGroup(component.id, component.pins[2]!, 'emitter');\n emitterGroup.position.set(0.05, 0, 0.4);\n emitterGroup.rotateX(Math.PI / 2);\n group.add(emitterGroup);\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n /**\n * Get config form definition for Transistor (T026)\n *\n * @returns Form definition with activationLogic boolean field\n */\n override getConfigFormDefinition(): ConfigFormDefinition | null {\n return {\n fields: [\n {\n key: 'activationLogic',\n label: 'Activation Logic',\n type: 'boolean',\n },\n {\n key: 'transitionSpan',\n label: 'Transition Span (ticks)',\n type: 'number',\n },\n {\n key: 'initializationOrder',\n label: 'Init Order',\n type: 'number',\n },\n ],\n };\n }\n\n /**\n * Map core config to form data (T026)\n * Converts \"positive\"/\"negative\" strings to boolean\n *\n * @param config - Core component config\n * @returns Form data with boolean activationLogic\n */\n override mapCoreConfigToForm(config: Map<string, string>): Map<string, any> {\n const formData = new Map<string, any>();\n const activationLogic = config.get('activationLogic');\n formData.set('activationLogic', activationLogic === 'positive');\n formData.set('transitionSpan', parseFloat(config.get('transitionSpan') || '1'));\n formData.set('initializationOrder', parseFloat(config.get('initializationOrder') || '0'));\n return formData;\n }\n\n /**\n * Map form data to core config (T026)\n * Converts boolean to \"positive\"/\"negative\" strings\n *\n * @param formData - Form data with boolean activationLogic\n * @returns Core config with string activationLogic\n */\n override mapFormToCoreConfig(formData: Map<string, any>): Map<string, string> {\n const config = new Map<string, string>();\n const activationLogic = formData.get('activationLogic');\n config.set('activationLogic', activationLogic ? 'positive' : 'negative');\n config.set('transitionSpan', formData.get('transitionSpan').toString());\n config.set('initializationOrder', formData.get('initializationOrder').toString() || null);\n return config;\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n // const fillerMesh = this.findFillerMesh(object3D);\n // if(!fillerMesh) return;\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'closed';\n } else {\n envelopeMesh.userData.initialState = 'open';\n }\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update Transistor animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The Transistor's current simulation state\n */\n override updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void {\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n if (!state) {\n if (envelopeMesh.userData.initialState === 'closed') {\n envelopeMesh.geometry = this.closedGeometry;\n envelopeMesh.material.emissiveIntensity =\n TransistorVisualFactory.TRANSISTOR_CLOSED_INTENSITY;\n } else {\n envelopeMesh.geometry = this.openGeometry;\n envelopeMesh.material.emissiveIntensity = 0;\n }\n return;\n }\n\n const transistorState = state as TransistorState;\n if (transistorState.isClosed) {\n envelopeMesh.geometry = this.closedGeometry;\n envelopeMesh.material.emissiveIntensity = TransistorVisualFactory.TRANSISTOR_CLOSED_INTENSITY;\n } else if (transistorState.isInTransition) {\n envelopeMesh.geometry = this.transientGeometry;\n envelopeMesh.material.emissiveIntensity =\n 0.5 * TransistorVisualFactory.TRANSISTOR_CLOSED_INTENSITY;\n } else {\n envelopeMesh.geometry = this.openGeometry;\n envelopeMesh.material.emissiveIntensity = 0;\n }\n }\n\n /**\n * Find the envelope mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The envelope mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'envelope'\n */\n private findEnvelopeMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let envelopeMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'envelope') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n envelopeMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n return envelopeMesh;\n }\n}\n","import {ComponentType} from \"simple-circuit-engine/core\";\nimport {\n type IFactoryRegistry,\n BatteryVisualFactory,\n LabelVisualFactory,\n LightbulbVisualFactory,\n RectangleLEDVisualFactory,\n RelayVisualFactory,\n SmallLEDVisualFactory,\n SwitchVisualFactory,\n TransistorVisualFactory\n} from \"./shared/components\";\n\n\n/**\n * Register all basic component visual factories in the given registry\n * Basic components are : Battery, Lightbulb, RectangleLED, Relay, SmallLED, Switch, Transistor\n * @public\n * @param registry\n */\nexport function registerBasicComponentsFactories(registry: IFactoryRegistry): void {\n registry\n .register(ComponentType.Battery, new BatteryVisualFactory())\n .register(ComponentType.Label, new LabelVisualFactory())\n .register(ComponentType.Lightbulb, new LightbulbVisualFactory())\n .register(ComponentType.RectangleLED, new RectangleLEDVisualFactory())\n .register(ComponentType.Relay, new RelayVisualFactory())\n .register(ComponentType.SmallLED, new SmallLEDVisualFactory())\n .register(ComponentType.Switch, new SwitchVisualFactory())\n .register(ComponentType.Transistor, new TransistorVisualFactory())\n}"],"names":["EventEmitter","event","callback","callbacks","index","payload","error","originalEmit","createGridHelper","size","divisions","colorCenterLine","colorGrid","grid","THREE","computeDivisionsForSize","basis","threshold","nearestWorldSnapPosition","position","worldToGridPosition","Position","gridToWorldPosition","worldToGridRotation","rotation","Rotation","gridToWorldRotation","worldToScreenPosition","worldPosition","camera","width","height","vector","x","y","isPointInScreenRect","rect","screen","RingGeometry","innerRadius","outerRadius","steps","shape","holePath","extrudeSettings","getNextSourceType","current","ENodeSourceType","BuildTool","controller","container","controls","hoveredElement","selection","previews","circuit","enodeId","componentId","wireId","screenPos","wire","nearestPoint","pos","worldPos","insertIndex","monoSelection","gridPosition","sourceEnodeId","enodeGroup","sourcePosition","previewWire","emit","targetEnodeId","hasSelected","targetWireId","targetType","pointIndex","originalPositions","p","gridPos","newPositions","wireDragState","finalPositions","result","w","object","newPosition","component","connectedWire","visual","enode","connectedWireId","initialPosition","branchingPoint","newAngle","positions","draggedIndex","draggedPos","node1","node2","endpoint1","endpoint2","i","otherPos","sources","pinId","hitbox","nextSourceType","screenPosition","AddComponentTool","type","forward","registry","types","currentIndex","newType","factory","tempComponent","Component","child","mat","previewBox","componentObjects","_id","componentGroup","componentBox","previousOverlap","Euler","delta","ctrlKey","MIN_SELECTION_RECT_SIZE","MultiSelectTool","selectionManager","shiftHeld","isSelected","circuitComponent","containerRect","screenX","screenY","startScreen","currentScreen","overlayElement","left","top","elementsInRect","newPreviewSet","id","screenRect","selectedEnodeIds","wireEnodeSelectionCount","componentObject3Ds","object3D","currentCount","enodeObject3Ds","count","components","enodes","wires","existing","totalCount","selectedIds","initialPositions","affectedWireIds","initialWireIntermediatePositions","dragStartWorld","elementId","initialPos","snappedPosition","componentObject3D","enodeObject3D","initialIntermediatePositions","updatedPositions","newPos","wireVisualManager","currentPosition","gridDelta","bounds","anchor","clipboardComponents","clipboardBranchingPoints","selectedEndpointIds","clipboardWires","relativeIntermediatePositions","cursorPosition","gridCursor","idRemap","createdComponentIds","clipComponent","newGridPos","newComponent","originalPinId","originalComponentId","pinIndex","newPinId","createdBranchingPointIds","clipBP","newEnode","createdWireIds","clipWire","newNode1","newNode2","newWire","absolutePositions","relPos","componentsMap","enodesMap","wiresMap","SelectionManager","objectId","a","b","aComponents","bComponents","aEnodes","bEnodes","aWires","bWires","userData","previousSelection","newSelection","ENodeType","data","CircuitWriter","sourceType","modelPosition","circuitEnode","addResult","positionObjects","config","pinSources","modelRotation","pinIdx","customSource","cmpPinId","pin","parameters","ComponentType","newSize","options","CameraOptions","Position3D","createPerspectiveCamera","aspect","camPos","camTarget","updateCamera","createAmbientLight","color","intensity","createDirectionalLight","light","setupSceneLights","scene","lights","ambient","main","fill","HitboxLayers","HoverManager","normalizedX","normalizedY","now","hitElement","componentHit","enabled","initialized","layer","hoverableType","objectType","intersections","intersection","obj","newHit","previousHit","BranchingPointVisualFactory","group","hitboxGeom","coneGeometry","coneMaterial","newColor","state","fallbackEmissive","createLine2Material","linewidth","LineMaterial","WireVisualManager","wireObject3Ds","material","wirePath","line","geometry","LineGeometry","Line2","wireIdsToUpdate","currentMaterial","wireLines","_wireId","startPosition","previewLine","endPosition","target","found","points","minDistance","segmentStart","segmentEnd","segmentDir","segmentLength","projection","clampedProjection","closestPoint","distance","clientPos","thresholdPx","containerRelativePos","nearestIndex","nearestDistance","pointScreenPos","startPos","endPos","enodeType","componentGroups","pinPosition","widthHalf","heightHalf","screenPos1","screenPos2","mapControlsOptions","defaultOptions","controllerOptions","engineOptions","createMapControls","MapControls","AbstractCircuitController","factoryRegistry","sharedResources","err","active","oldCircuitName","bound","unhoverPreviousElement","element","hoverElement","previousElement","oldPosition","_event","_width","_height","Controller","parent","property","className","elementType","e","name","disabled","show","min","max","step","decimals","listen","curValue","value","BooleanController","normalizeColorString","string","match","STRING","v","INT","ARRAY","rgbScale","int","r","g","OBJECT","FORMATS","getColorFormat","format","ColorController","tryParse","newValue","FunctionController","NumberController","stepExplicit","explicit","percent","onInput","increment","onKeyDown","onWheel","testingForVerticalDrag","initClientX","initClientY","prevClientY","initValue","dragDelta","DRAG_THRESH","onMouseDown","onMouseMove","onMouseUp","dx","dy","onFocus","onBlur","map","c","d","setValueFromX","clientX","mouseDown","mouseMove","mouseUp","testingForScroll","prevClientX","beginTouchDrag","onTouchStart","onTouchMove","onTouchEnd","callOnFinishChange","WHEEL_DEBOUNCE_TIME","wheelFinishChangeTimeout","axis","deltaX","deltaY","mult","offset","root","OptionController","$option","StringController","stylesheet","_injectStyles","cssContent","injected","before","stylesInjected","GUI","autoPlace","title","closeFolders","injectStyles","touchStyles","$1","initialValue","folder","recursive","f","open","closed","initialHeight","onTransitionEnd","targetHeight","changedGUI","controllers","folders","ConfigPanelManager","editComponentConfig","_camera","_domElement","formDef","PANEL_WIDTH","OFFSET_X","VIEWPORT_PADDING","viewportWidth","viewportHeight","formData","key","field","_component","formDataMap","coreConfig","CircuitController","previousTool","tool","selected","_data","componentType","toolType","cursorType","mesh","pinGroup","newConfig","CircuitRunnerController","SIMULATION_SPEED","behaviorRegistry","tps","previousSpeed","clampedTps","transitionUserSpanMs","tickCount","TRANSITION_DEFAULTS","CircuitRunner","dirty","wireState","materialState","enodeState","enodeObject","emissiveColor","componentObject","clickedElement","transitionUserSpan","command","_clickedElement","CircuitEngine","mapControls","hoverManager","branchingPointVisualFactory","mode","previousMode","gridSize","gridDivisions","h","FactoryRegistry","fallbackFactory","ComponentVisualFactoryBase","_object3D","_config","label","groupId","depth","_state","COLOR_PRESETS","isHexColor","hexToPresetOrHex","hex","lowerHex","presetHex","presetOrHexToHex","DefaultVisualFactory","boxGeometry","boxMaterial","box","hexColor","colorHex","BatteryVisualFactory","cylinderGeometry","cylinderMaterial","cylinder","cathodeGroup","anodeGroup","LabelVisualFactory","text","textMesh","textGeometry","canvas","ctx","pixelRatio","scaledFontSize","scaledPadding","displayText","metrics","textWidth","textHeight","texture","worldWidth","worldHeight","BoxGeometry","newText","clampedSize","LightbulbVisualFactory","baseMaterial","baseGeometry","base","bulbMaterial","bulbGeometry","bulb","pin1Group","pin2Group","scale","bulbMesh","RectangleLEDVisualFactory","ledMaterial","ledGeometry","led","inputPinGroup","outputPinGroup","idleColor","activeColor","ledMesh","inputPin","outputPin","idleColorHex","hwRatio","ywRatio","pinScale","RelayVisualFactory","coilGeometry","coilMaterial","coil","cmdInGroup","cmdOutGroup","powerInGeometry","powerMaterial","powerInPole","powerInGroup","powerOutGeometry","powerOutPole","powerOutGroup","contactorGroup","contactorMaterial","contactorGeometry","contactor","activationLogic","relayState","targetRotation","SmallLEDVisualFactory","SwitchVisualFactory","inputPoleGeometry","poleMaterial","inputPole","outputPoleGeometry","outputPole","initialState","switchState","TransistorVisualFactory","envelopeMaterial","envelope","collectorGroup","baseGroup","emitterGroup","envelopeMesh","transistorState","registerBasicComponentsFactories"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","x_google_ignoreList":[17]}
|