simple-circuit-engine 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-CIq_kgaw.js","sources":["../src/scene/shared/EventEmitter.ts","../src/scene/shared/utils/GeometryUtils.ts","../src/scene/static/tools/ComponentPickerWidget.ts","../src/scene/static/tools/BuildTool.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/tools/ConfigPanelWidget.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/GroupedFactoryRegistry.ts","../src/scene/shared/components/basic/BatteryVisualFactory.ts","../src/scene/shared/components/basic/LabelVisualFactory.ts","../src/scene/shared/components/basic/LightbulbVisualFactory.ts","../src/scene/shared/components/basic/RectangleLEDVisualFactory.ts","../src/scene/shared/components/basic/RelayVisualFactory.ts","../src/scene/shared/components/basic/SmallLEDVisualFactory.ts","../src/scene/shared/components/basic/SwitchVisualFactory.ts","../src/scene/shared/components/basic/DoubleThrowSwitchVisualFactory.ts","../src/scene/shared/components/gates/InverterVisualFactory.ts","../src/scene/shared/components/gates/NandGateVisualFactory.ts","../src/scene/shared/components/gates/Nand4GateVisualFactory.ts","../src/scene/shared/components/gates/Nand8GateVisualFactory.ts","../src/scene/shared/components/gates/NorGateVisualFactory.ts","../src/scene/shared/components/gates/Nor4GateVisualFactory.ts","../src/scene/shared/components/gates/Nor8GateVisualFactory.ts","../src/scene/shared/components/gates/XorGateVisualFactory.ts","../src/scene/shared/components/gates/Xor4GateVisualFactory.ts","../src/scene/shared/components/gates/Xor8GateVisualFactory.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 * convenience to control standard rotations of meshes on X-Z plan\n */\nexport type Direction2D = 'right' | 'bottom' | 'left' | 'top';\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 depth (y axis)\n * @param innerRadius\n * @param outerRadius\n * @param depth\n * @param steps\n * @constructor\n */\nexport function RingGeometry(\n innerRadius: number,\n outerRadius: number,\n depth: 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 // Extrude settings\n const extrudeSettings = {\n depth: depth,\n bevelEnabled: false,\n steps: steps,\n };\n // if innerRadius is less than 10% of outerRadius we consider the geometry full (inner hole would be too small)\n if (innerRadius < 0.1 * outerRadius) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\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 // Create the extruded geometry\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n\n/**\n * Internal variant of AndGateGeometry for tall gates where width ≤ height / 2.\n * In this regime a standard semicircle does not fit, so the entire right side is\n * a single circular arc passing through the top-left corner (-halfW, +halfH),\n * the output tip (+halfW, 0), and the bottom-left corner (-halfW, -halfH).\n *\n * The arc center and radius are derived analytically from those three points.\n * By symmetry the center lies on the x-axis: cx = -halfH² / (4·halfW).\n * The inner hole reuses the same formula applied to the inset dimensions\n * (halfW - thickness, halfH - thickness), so the right-side wall is uniform.\n *\n * @param width - Total width, from left flat edge to rightmost arc point\n * @param height - Total height; also determines the arc radius (= height / 2)\n * @param thickness - Wall thickness of the gate shell\n * @param depth - Extrusion depth\n * @param steps - Number of extrusion steps\n */\nfunction _AndGateTallGeometry(\n width: number,\n height: number,\n thickness: number,\n depth: number,\n steps: number\n): ExtrudeGeometry {\n if (width > height / 2) {\n throw new Error(\n 'this method only handle the tall case : use regular AndGateGeometry in this case.'\n );\n }\n const halfW = width / 2;\n const halfH = height / 2;\n // Unique circle through (-halfW, ±halfH) and (halfW, 0), center on x-axis.\n // From (cx - halfW)² = (cx + halfW)² + halfH² → cx = -halfH² / (4·halfW)\n const cx = -(halfH * halfH) / (4 * halfW);\n const radius = (halfH * halfH + 4 * halfW * halfW) / (4 * halfW);\n // x-distance from center to the back-left corners; always > 0 in the tall regime (halfH ≥ 2·halfW)\n const xComp = -halfW - cx; // = (halfH² - 4·halfW²) / (4·halfW)\n const angle_top = Math.atan2(halfH, xComp);\n\n // Outer shape: flat left side (up) + single right arc CW from top to bottom\n const shape = new THREE.Shape();\n shape.moveTo(-halfW, -halfH);\n shape.lineTo(-halfW, halfH); // left flat side, going up\n shape.absarc(cx, 0, radius, angle_top, -angle_top, true); // right arc CW, sweeping through (halfW, 0)\n // arc ends exactly at (-halfW, -halfH) = moveTo → Three.js auto-closes\n\n const extrudeSettings = {\n depth,\n bevelEnabled: false,\n steps,\n };\n // if thickness is superior to 90% of halfH or here we consider the geometry full (inner hole would be too small)\n if (thickness > 0.9 * Math.min(halfH, halfW)) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n\n // Inner hole: same formula applied to inset dimensions, opposite winding (CW overall)\n // Inner right output point: (halfW - thickness, 0); inner corners: (-halfW + thickness, ±(halfH - thickness))\n const innerHalfW = halfW - thickness;\n const innerHalfH = halfH - thickness;\n const cx_inner = -(innerHalfH * innerHalfH) / (4 * innerHalfW);\n const radius_inner = (innerHalfH * innerHalfH + 4 * innerHalfW * innerHalfW) / (4 * innerHalfW);\n const xComp_inner = -innerHalfW - cx_inner; // = (innerHalfH² - 4·innerHalfW²) / (4·innerHalfW)\n const angle_top_inner = Math.atan2(innerHalfH, xComp_inner);\n\n // Hole: left side going DOWN + CCW right arc (bottom to top, sweeping right)\n const hole = new THREE.Path();\n hole.moveTo(-halfW + thickness, innerHalfH);\n hole.lineTo(-halfW + thickness, -innerHalfH); // inner left side, going down\n hole.absarc(cx_inner, 0, radius_inner, -angle_top_inner, angle_top_inner, false); // CCW, sweeping right\n // arc ends at (-halfW + thickness, innerHalfH) = moveTo → Three.js auto-closes\n shape.holes.push(hole);\n\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n\n/**\n * Create an ExtrudeGeometry for the body of an AND gate.\n * Shape is centered at origin: flat side on the left, semicircle on the right,\n * matching the standard logic gate schematic representation.\n * Handles both standard (width > height / 2) and tall (width ≤ height / 2) proportions.\n *\n * Input pins attach on the left flat side (x = -width/2).\n * Output pin attaches at the rightmost point of the arc (x = +width/2).\n *\n * The thickness parameter controls a visual state trick:\n * - LOW state: thin thickness → gate appears as an empty shell\n * - HIGH state: thick thickness → gate appears filled\n * - TRANSITIONING: medium thickness → gate appears half-filled\n *\n * @param width - Total width, from left flat edge to rightmost arc point\n * @param height - Total height; also determines the arc radius (= height / 2)\n * @param thickness - Wall thickness of the gate shell\n * @param depth - Extrusion depth\n * @param steps - Number of extrusion steps\n * @constructor\n */\nexport function AndGateGeometry(\n width: number,\n height: number,\n thickness: number,\n depth: number,\n steps: number = 1\n): ExtrudeGeometry {\n // Tall gate: the semicircle does not fit when width ≤ height / 2; use the arc variant\n if (width <= height / 2) {\n return _AndGateTallGeometry(width, height, thickness, depth, steps);\n }\n\n const halfW = width / 2;\n const halfH = height / 2;\n\n // The semicircle center sits at the boundary between the rectangular and curved portions\n const arcCenterX = halfW - halfH;\n\n // Outer shape: left flat side, top edge, clockwise right semicircle, bottom edge\n const shape = new THREE.Shape();\n shape.moveTo(-halfW, -halfH);\n shape.lineTo(-halfW, halfH); // left flat side, going up\n shape.lineTo(arcCenterX, halfH); // top edge, going right\n shape.absarc(arcCenterX, 0, halfH, Math.PI / 2, -Math.PI / 2, true); // right semicircle, clockwise\n shape.lineTo(-halfW, -halfH);\n\n const extrudeSettings = {\n depth,\n bevelEnabled: false,\n steps,\n };\n // if thickness is superior to 90% of halfH or halfW we consider the geometry full (inner hole would be too small)\n if (thickness > 0.9 * Math.min(halfH, halfW)) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n\n // Inner hole: same AND gate shape shrunk by thickness, traced with opposite winding\n // (CCW arc from bottom to top) so Three.js treats it as a hole\n const innerHalfH = halfH - thickness;\n const hole = new THREE.Path();\n hole.moveTo(-halfW + thickness, -innerHalfH);\n hole.lineTo(arcCenterX, -innerHalfH); // inner bottom edge, going right\n hole.absarc(arcCenterX, 0, innerHalfH, -Math.PI / 2, Math.PI / 2, false); // inner right semicircle, counter-clockwise\n hole.lineTo(-halfW + thickness, innerHalfH); // inner top edge, going left\n // Three.js auto-closes back to moveTo point (inner left side, going down)\n shape.holes.push(hole);\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n\n/**\n * Internal variant of OrGateGeometry for tall gates where width ≤ height / 2.\n * In this regime the right output semicircle does not fit, so the right side becomes\n * a single circular arc through the back-left corners (-halfW, ±halfH) and (halfW, 0),\n * exactly as in _AndGateTallGeometry — the only difference is the back (left) side\n * which remains the OR gate's characteristic concave arc.\n *\n * The inner hole back arc uses the same concentric offset trick (fixed backWallThickness).\n * The inner right arc is solved from the three points it must pass through:\n * (inner_back_x, ±innerHalfH) and (halfW - thickness, 0), where inner_back_x is where\n * the concentric back arc intersects y = ±innerHalfH. The circle center is found\n * analytically from (p - cx_r)² = (q - cx_r)² + innerHalfH² where p = halfW - thickness\n * and q = inner_back_x.\n */\nfunction _OrGateTallGeometry(\n width: number,\n height: number,\n thickness: number,\n depth: number,\n steps: number\n): ExtrudeGeometry {\n if (width > height / 2) {\n throw new Error(\n '_OrGateTallGeometry only handles the tall case: use regular OrGateGeometry instead.'\n );\n }\n const halfW = width / 2;\n const halfH = height / 2;\n\n // Back (left) concave arc — identical to standard OrGateGeometry\n const backInset = halfH * 0.4;\n const u_b = (halfH * halfH - backInset * backInset) / (2 * backInset);\n const cx_b = -halfW - u_b;\n const r_b = u_b + backInset;\n const angle_b = Math.atan2(halfH, u_b);\n\n // Right arc: unique circle through (-halfW, ±halfH) and (halfW, 0), center on x-axis\n // Same derivation as _AndGateTallGeometry: cx = -halfH² / (4·halfW)\n const cx = -(halfH * halfH) / (4 * halfW);\n const radius = (halfH * halfH + 4 * halfW * halfW) / (4 * halfW);\n const xComp = -halfW - cx;\n const angle_top = Math.atan2(halfH, xComp);\n\n // Outer shape: concave back arc (CCW) flows directly into right arc (CW) — no horizontal edges\n const shape = new THREE.Shape();\n shape.moveTo(-halfW, -halfH);\n shape.absarc(cx_b, 0, r_b, -angle_b, angle_b, false); // concave back, CCW bottom to top\n shape.absarc(cx, 0, radius, angle_top, -angle_top, true); // right arc CW, top to bottom through (halfW, 0)\n // arc ends at (-halfW, -halfH) = moveTo → Three.js auto-closes\n\n const extrudeSettings = { depth, bevelEnabled: false, steps };\n // if thickness is superior to 90% of halfH or halfW we consider the geometry full (inner hole would be too small)\n if (thickness > 0.9 * Math.min(halfH, halfW)) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n\n // Inner hole — opposite winding (CW overall)\n const innerHalfH = halfH - thickness;\n\n // Inner back arc: concentric offset (same center cx_b, radius += backWallThickness)\n const backWallThickness = Math.max(0.1, thickness / 2);\n const r_b_inner = r_b + backWallThickness;\n const inner_x_comp = Math.sqrt(r_b_inner * r_b_inner - innerHalfH * innerHalfH);\n const angle_b_inner = Math.atan2(innerHalfH, inner_x_comp);\n const inner_back_x = cx_b + inner_x_comp; // x where inner back arc meets y = ±innerHalfH\n\n // Inner right arc: passes through (inner_back_x, ±innerHalfH) and (halfW - thickness, 0)\n // Center on x-axis at cx_r, solved from (p - cx_r)² = (q - cx_r)² + innerHalfH²\n // → cx_r = (q² + innerHalfH² - p²) / (2·(q - p))\n const p = halfW - thickness; // inner output tip x-coordinate\n const q = inner_back_x;\n const cx_r = (q * q + innerHalfH * innerHalfH - p * p) / (2 * (q - p));\n const radius_r = p - cx_r;\n const angle_top_r = Math.atan2(innerHalfH, inner_back_x - cx_r);\n\n // Hole: CW back arc (top → bottom) then CCW right arc (bottom → top, sweeping through output tip)\n const hole = new THREE.Path();\n hole.moveTo(inner_back_x, innerHalfH);\n hole.absarc(cx_b, 0, r_b_inner, angle_b_inner, -angle_b_inner, true); // CW, top to bottom\n hole.absarc(cx_r, 0, radius_r, -angle_top_r, angle_top_r, false); // CCW, bottom to top\n // arc ends at (inner_back_x, innerHalfH) = moveTo → Three.js auto-closes\n shape.holes.push(hole);\n\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n\n/**\n * Create an ExtrudeGeometry for the body of an OR gate.\n * Same structure as AndGateGeometry but the left side is a concave arc (curves inward)\n * instead of a flat edge, matching the standard logic gate schematic representation.\n * Handles both standard (width > height / 2) and tall (width ≤ height / 2) proportions.\n *\n * Input pins attach on the left curved side (nominally at x = -width/2).\n * Output pin attaches at the rightmost point of the right arc (x = +width/2).\n *\n * The thickness parameter controls the same visual state trick as AndGateGeometry:\n * - LOW state: thin thickness → gate appears as an empty shell\n * - HIGH state: thick thickness → gate appears filled\n * - TRANSITIONING: medium thickness → gate appears half-filled\n *\n * Back arc geometry: the concave left side bows inward (rightward) by backInset = halfH * 0.4.\n * The arc center sits far to the left; u_b is its x-distance to the back-left corners.\n * The inner hole back arc is concentric with the outer (same center, radius += 0.1), giving a\n * truly constant perpendicular wall thickness of 0.1 along the entire back curve, independent\n * of the thickness parameter.\n *\n * @param width - Total width, from leftmost back curve point to rightmost arc point\n * @param height - Total height; also determines the right arc radius (= height / 2)\n * @param thickness - Wall thickness of the gate shell\n * @param depth - Extrusion depth\n * @param steps - Number of extrusion steps\n * @constructor\n */\nexport function OrGateGeometry(\n width: number,\n height: number,\n thickness: number,\n depth: number,\n steps: number = 1\n): ExtrudeGeometry {\n // Tall gate: the output semicircle does not fit when width ≤ height / 2; use the arc variant\n if (width <= height / 2) {\n return _OrGateTallGeometry(width, height, thickness, depth, steps);\n }\n\n const halfW = width / 2;\n const halfH = height / 2;\n\n // Back (left) concave arc: midpoint bows rightward by backInset from the left edge\n const backInset = halfH * 0.4;\n // u_b: x-distance from arc center (cx_b, 0) to the back-left corners (-halfW, ±halfH)\n // Derived from: arc passes through (-halfW, ±halfH) and midpoint (-halfW + backInset, 0)\n const u_b = (halfH * halfH - backInset * backInset) / (2 * backInset);\n const cx_b = -halfW - u_b; // arc center, far to the left of the gate\n const r_b = u_b + backInset; // = sqrt(u_b² + halfH²), by construction\n const angle_b = Math.atan2(halfH, u_b); // angle from center to the back-left corners\n\n // Right output semicircle center (same as AndGateGeometry)\n const arcCenterX = halfW - halfH;\n\n // Outer shape: concave back arc (CCW, bottom to top) + top edge + CW right semicircle + bottom edge\n const shape = new THREE.Shape();\n shape.moveTo(-halfW, -halfH);\n shape.absarc(cx_b, 0, r_b, -angle_b, angle_b, false); // concave back, CCW bottom to top\n shape.lineTo(arcCenterX, halfH); // top edge, going right\n shape.absarc(arcCenterX, 0, halfH, Math.PI / 2, -Math.PI / 2, true); // right output semicircle, CW\n shape.lineTo(-halfW, -halfH); // bottom edge, back to start\n\n const extrudeSettings = { depth, bevelEnabled: false, steps };\n // if thickness is superior to 90% of halfH or halfW we consider the geometry full (inner hole would be too small)\n if (thickness > 0.9 * Math.min(halfH, halfW)) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n\n // Inner hole: opposite winding (CW overall)\n const innerHalfH = halfH - thickness;\n\n // Back arc inner wall: fixed perpendicular thickness, independent of the `thickness` parameter.\n // Since both arcs share the same center (cx_b, 0), adding backWallThickness to r_b gives a\n // concentric arc at exactly that perpendicular distance everywhere along the curve.\n const backWallThickness = Math.max(0.1, thickness / 2);\n const r_b_inner = r_b + backWallThickness;\n // x-component from arc center to the inner arc at y = ±innerHalfH\n const inner_x_comp = Math.sqrt(r_b_inner * r_b_inner - innerHalfH * innerHalfH);\n const angle_b_inner = Math.atan2(innerHalfH, inner_x_comp);\n const inner_back_x = cx_b + inner_x_comp; // x where inner back arc meets inner top/bottom edges\n\n const hole = new THREE.Path();\n hole.moveTo(inner_back_x, innerHalfH);\n hole.absarc(cx_b, 0, r_b_inner, angle_b_inner, -angle_b_inner, true); // CW from top to bottom\n hole.lineTo(arcCenterX, -innerHalfH); // inner bottom edge, going right\n hole.absarc(arcCenterX, 0, innerHalfH, -Math.PI / 2, Math.PI / 2, false); // inner right semicircle, CCW\n hole.lineTo(inner_back_x, innerHalfH); // inner top edge, going left\n // Three.js auto-closes back to moveTo point (inner left side, going down)\n shape.holes.push(hole);\n\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n\n/**\n * Create an ExtrudeGeometry for the XOR gate tail — the distinctive extra curved bar\n * placed to the left of an OrGateGeometry body to form the full XOR gate symbol.\n *\n * Back-arc parameters (backInset, u_b, cx_b, r_b, angle_b) are identical to those in\n * OrGateGeometry so this geometry aligns correctly when placed at the same centre.\n *\n * Note: the tail arc's centre is shifted left by tailWidth (radius stays constant = r_b), so\n * the tail always spans the full gate height regardless of tailWidth.\n * For bars to be visible, barsSeparation must be less than orHeight − 2 × thickness.\n *\n * @param orWidth - Width of the paired OR gate body\n * @param orHeight - Height of the paired OR gate body\n * @param tailWidth - How far left the tail arc's corners are from the OR gate's left corners\n * @param thickness - Wall thickness of the arc shell AND height of each bar\n * @param barsSeparation - Vertical gap between the two bars (centred on y = 0)\n * @param depth - Extrusion depth\n * @param steps - Number of extrusion steps\n */\nexport function XorGateTailGeometry(\n orWidth: number,\n orHeight: number,\n tailWidth: number,\n thickness: number,\n barsSeparation: number,\n depth: number,\n steps: number = 1\n): ExtrudeGeometry {\n const halfW = orWidth / 2;\n const halfH = orHeight / 2;\n\n // OR gate back-arc parameters — identical to OrGateGeometry\n const backInset = halfH * 0.4;\n const u_b = (halfH * halfH - backInset * backInset) / (2 * backInset);\n const cx_b = -halfW - u_b;\n const r_b = u_b + backInset;\n const angle_b = Math.atan2(halfH, u_b);\n\n // Tail arc: SAME radius r_b and angular sweep ±angle_b as the OR gate back arc,\n // but centre shifted left by tailWidth.\n // • arc corners land at (−halfW − tailWidth, ±halfH) — full gate height, always\n // • r_b never changes → never negative regardless of tailWidth value\n // • curvature is identical to the OR gate back arc (concentric shift of the centre)\n const cx_b_tail = cx_b - tailWidth; // = −(halfW + u_b + tailWidth)\n\n // Inner face of the arc shell: larger radius (further right from cx_b_tail = toward OR gate)\n const r_inner = r_b + thickness;\n\n // Corner x of the outer arc at y = ±halfH (= −halfW − tailWidth)\n const x_outer_corner = cx_b_tail + r_b * Math.cos(angle_b);\n // Flat right face aligned with the OR gate left-corner plane\n const x_flat = -halfW;\n\n // Bar vertical boundaries\n const y3 = barsSeparation / 2; // inner edge of bars (middle-gap boundary)\n const y4 = y3 + thickness; // outer edge of bars\n\n // x-coordinate and angle on the inner arc r_inner at height y\n const xInner = (y: number): number =>\n cx_b_tail + Math.sqrt(Math.max(0, r_inner * r_inner - y * y));\n const thetaInner = (y: number): number =>\n Math.atan2(y, Math.sqrt(Math.max(0, r_inner * r_inner - y * y)));\n\n // Whether bars and top/bottom caps are geometrically feasible given the parameters\n const barsExist = y3 < halfH && xInner(y3) < x_flat;\n const capsExist = barsExist && y4 < halfH; // caps sit above/below the bars inside the shape\n\n const extrudeSettings = { depth, bevelEnabled: false, steps };\n\n // Single closed CCW path — NO holes (avoids Three.js hole-border artefacts).\n // Strategy: trace the full solid boundary directly.\n // moveTo(x_outer_corner, -halfH)\n // EAST along bottom → NORTH up the right side (CCW inner arc + bar kinks) → WEST along top → CW outer arc SOUTH\n //\n // Three cases for the right side:\n // • No bars : single CCW inner arc from −halfH to +halfH\n // • Bars, no caps : flat face spans −halfH→+halfH, split by inner arc at ±y3\n // • Bars + caps : inner arc sections join bar segments between ±y3 and ±y4\n\n const shape = new THREE.Shape();\n shape.moveTo(x_outer_corner, -halfH);\n\n if (!barsExist) {\n // ── arc wall only ──────────────────────────────────────────────────────────\n shape.lineTo(xInner(-halfH), -halfH); // E — arc wall bottom\n shape.absarc(cx_b_tail, 0, r_inner, thetaInner(-halfH), thetaInner(halfH), false); // N — CCW inner arc all the way up\n } else if (!capsExist) {\n // ── bars reach the top/bottom of the shape (no cap regions) ───────────────\n // Flat face starts right at y = ±halfH; inner arc only spans the middle gap.\n shape.lineTo(x_flat, -halfH); // E — bottom edge spans arc wall + bar\n shape.lineTo(x_flat, -y3); // N — right face of bottom bar\n shape.lineTo(xInner(-y3), -y3); // W — top of bottom bar → inner arc\n shape.absarc(cx_b_tail, 0, r_inner, thetaInner(-y3), thetaInner(y3), false); // N — CCW inner arc through gap\n shape.lineTo(x_flat, y3); // E — bottom of top bar\n shape.lineTo(x_flat, halfH); // N — right face of top bar\n } else {\n // ── full shape: arc wall + top & bottom caps + two bars ───────────────────\n shape.lineTo(xInner(-halfH), -halfH); // E — arc wall bottom\n shape.absarc(cx_b_tail, 0, r_inner, thetaInner(-halfH), thetaInner(-y4), false); // N — CCW inner arc to bottom cap top\n shape.lineTo(x_flat, -y4); // E — bottom of bottom bar\n shape.lineTo(x_flat, -y3); // N — right face of bottom bar\n shape.lineTo(xInner(-y3), -y3); // W — top of bottom bar → inner arc\n shape.absarc(cx_b_tail, 0, r_inner, thetaInner(-y3), thetaInner(y3), false); // N — CCW inner arc through gap\n shape.lineTo(x_flat, y3); // E — bottom of top bar\n shape.lineTo(x_flat, y4); // N — right face of top bar\n shape.lineTo(xInner(y4), y4); // W — top of top bar → inner arc\n shape.absarc(cx_b_tail, 0, r_inner, thetaInner(y4), thetaInner(halfH), false); // N — CCW inner arc to top\n }\n\n shape.lineTo(x_outer_corner, halfH); // W — top edge\n shape.absarc(cx_b_tail, 0, r_b, angle_b, -angle_b, true); // S — CW outer arc down (left side)\n // Three.js auto-closes back to moveTo at (x_outer_corner, -halfH)\n\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n\n/**\n * Create an ExtrudeGeometry shaped like an L (or mirrored L) with a configurable\n * angle between the two arms.\n *\n * Default orientation (`invert = false`) produces a `|_`-like shape:\n * base arm extends to the right, stem arm extends upward at the given angle.\n * When `invert = true` the shape is mirrored horizontally (`_|`-like):\n * base arm extends to the left, stem arm mirrors accordingly.\n *\n * The `angle` parameter (in degrees) controls the inner angle between the two arms:\n * - 90° → standard right-angle L\n * - 120° → obtuse junction (`\\_`-like)\n * - 60° → acute junction\n *\n * Both the inner (concave) and outer (convex) junction corners are rounded\n * equally with `junctionRadius` (similar to CSS border-radius).\n * When 0 both corners are sharp. The arc sweep adapts to the angle: (180° − angle).\n *\n * The geometry is centered on its bounding box.\n *\n * At 90°, `width` and `height` correspond exactly to the bounding box dimensions.\n * At other angles the bounding box changes but the arm lengths remain consistent:\n * base inner arm = width − thickness, stem inner arm = height − thickness.\n *\n * @param width - Base arm length (bounding-box width at 90°)\n * @param height - Stem arm length (bounding-box height at 90°)\n * @param thickness - Arm thickness of the L\n * @param angle - Inner angle between the two arms, in degrees (typically 30–150)\n * @param invert - If true, mirror horizontally\n * @param junctionRadius - Radius of the rounded junction corners, inner and outer (0 = sharp)\n * @param depth - Extrusion depth\n * @param steps - Number of extrusion steps\n */\nexport function LGeometry(\n width: number,\n height: number,\n thickness: number,\n angle: number,\n invert: boolean,\n junctionRadius: number,\n depth: number,\n steps: number = 1\n): ExtrudeGeometry {\n const t = thickness;\n const alpha = THREE.MathUtils.degToRad(angle);\n const halfAlpha = alpha / 2;\n const cosA = Math.cos(alpha);\n const sinA = Math.sin(alpha);\n const cotHalf = Math.cos(halfAlpha) / Math.sin(halfAlpha);\n\n // Inner arm lengths from junction inner corner to arm tips\n const W = width - t;\n const H = height - t;\n\n // Clamp junction radius: tangent points must stay within both arms\n // Tangent distance from inner corner along each arm = r · cot(α/2)\n const maxR = cotHalf > 0 ? Math.min(W, H) / cotHalf : Infinity;\n const r = Math.min(Math.max(0, junctionRadius), maxR);\n\n // Inner arc center offset from inner corner along each arm = r · cot(α/2)\n const arcCX = r * cotHalf;\n\n // Outer arc center: at distance r inside the polygon from both outer edges\n // Center = ((r − t) · cotHalf, r − t) for non-inverted\n const outerCX = (r - t) * cotHalf;\n const outerCY = r - t;\n\n const shape = new THREE.Shape();\n\n if (!invert) {\n // Base arm extends RIGHT, stem arm at angle α from base\n // All coordinates relative to the inner junction corner at origin, CCW winding\n\n if (r > 0) {\n // Start at outer base tangent (on base outer edge, near junction)\n shape.moveTo(outerCX, -t);\n shape.lineTo(W, -t); // base outer edge →\n shape.lineTo(W, 0); // base tip cap ↑\n shape.lineTo(arcCX, 0); // base inner edge ← to inner arc tangent\n shape.absarc(arcCX, r, r, -Math.PI / 2, alpha + Math.PI / 2, true); // CW inner arc\n shape.lineTo(H * cosA, H * sinA); // stem tip inner\n shape.lineTo(H * cosA - t * sinA, H * sinA + t * cosA); // stem tip outer\n // Stem outer edge ↙ to outer arc tangent\n shape.lineTo(outerCX - r * sinA, outerCY + r * cosA);\n // CCW outer arc (convex corner rounding)\n shape.absarc(outerCX, outerCY, r, alpha + Math.PI / 2, -Math.PI / 2, false);\n // auto-close back to outer base tangent\n } else {\n shape.moveTo(-t * cotHalf, -t); // outer junction corner\n shape.lineTo(W, -t); // base outer edge →\n shape.lineTo(W, 0); // base tip cap ↑\n shape.lineTo(0, 0); // sharp inner corner\n shape.lineTo(H * cosA, H * sinA); // stem tip inner\n shape.lineTo(H * cosA - t * sinA, H * sinA + t * cosA); // stem tip outer\n // auto-close: stem outer edge back to outer junction corner\n }\n } else {\n // Mirrored: base arm extends LEFT, stem arm mirrored\n // Stem direction becomes (-cosA, sinA), outward perpendicular (sinA, cosA)\n\n if (r > 0) {\n // Start at outer stem tangent (on stem outer edge, near junction)\n shape.moveTo(-outerCX + r * sinA, outerCY + r * cosA);\n shape.lineTo(-H * cosA + t * sinA, H * sinA + t * cosA); // stem outer edge\n shape.lineTo(-H * cosA, H * sinA); // stem tip inner (cap)\n shape.lineTo(-arcCX * cosA, arcCX * sinA); // stem inner edge to inner arc tangent\n shape.absarc(-arcCX, r, r, Math.PI / 2 - alpha, -Math.PI / 2, true); // CW inner arc\n shape.lineTo(-W, 0); // base tip inner\n shape.lineTo(-W, -t); // base tip outer (cap)\n // Base outer edge → to outer arc tangent\n shape.lineTo(-outerCX, -t);\n // CCW outer arc (convex corner rounding)\n shape.absarc(-outerCX, outerCY, r, -Math.PI / 2, Math.PI / 2 - alpha, false);\n // auto-close back to outer stem tangent\n } else {\n shape.moveTo(t * cotHalf, -t); // outer junction corner\n shape.lineTo(-H * cosA + t * sinA, H * sinA + t * cosA); // stem tip outer\n shape.lineTo(-H * cosA, H * sinA); // stem tip inner (cap)\n shape.lineTo(0, 0); // sharp inner corner\n shape.lineTo(-W, 0); // base tip inner\n shape.lineTo(-W, -t); // base tip outer (cap)\n // auto-close: base outer edge → back to outer junction corner\n }\n }\n\n const geometry = new THREE.ExtrudeGeometry(shape, { depth, bevelEnabled: false, steps });\n /*geometry.rotateX(-0.23);\n geometry.rotateY(0.95);\n geometry.rotateZ(-0.22);*/\n return geometry;\n}\n\nexport function CyclicTrapezoidGeometry(\n width: number,\n tailHeight: number,\n headHeight: number,\n thickness: number,\n depth: number,\n steps: number = 1\n): ExtrudeGeometry {\n const halfW = width / 2;\n const halfTailH = tailHeight / 2;\n const halfHeadH = headHeight / 2;\n\n // Outer shape (CCW): BL → BR (→ TR if trapezoid) → TL\n const shape = new THREE.Shape();\n shape.moveTo(-halfW, -halfTailH);\n if (headHeight > 0) {\n shape.lineTo(halfW, -halfHeadH);\n shape.lineTo(halfW, halfHeadH);\n } else {\n shape.lineTo(halfW, 0);\n }\n shape.lineTo(-halfW, halfTailH);\n // Three.js auto-closes back to moveTo\n\n const extrudeSettings = { depth, bevelEnabled: false, steps };\n\n if (thickness > 0.9 * Math.min(halfTailH, halfW)) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n\n // Perpendicular inset of the slanted edges.\n // Top slant from (-halfW, halfTailH) to (halfW, halfHeadH):\n // dH = halfTailH − halfHeadH (height drop along the slant, ≥ 0)\n // L = slant length = √(width² + dH²)\n // Inner top-left y = halfTailH − thickness·(L + dH) / width\n // Inner top-right y = halfHeadH − thickness·(L − dH) / width\n // (bottom corners symmetric about y = 0)\n const dH = halfTailH - halfHeadH;\n const L = Math.sqrt(width * width + dH * dH);\n\n const innerTailHalfH = halfTailH - (thickness * (L + dH)) / width;\n if (innerTailHalfH <= 0) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n\n const hole = new THREE.Path();\n\n if (headHeight > 0) {\n const innerHeadHalfH = halfHeadH - (thickness * (L - dH)) / width;\n if (innerHeadHalfH <= 0 || width - 2 * thickness <= 0) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n // CW hole: TL → BL → BR → TR\n hole.moveTo(-halfW + thickness, innerTailHalfH);\n hole.lineTo(-halfW + thickness, -innerTailHalfH);\n hole.lineTo(halfW - thickness, -innerHeadHalfH);\n hole.lineTo(halfW - thickness, innerHeadHalfH);\n } else {\n // Triangle case: top and bottom inner slants meet at a single tip on the x-axis.\n // tipX = halfW − thickness·L / halfTailH\n const tipX = halfW - (thickness * L) / halfTailH;\n if (tipX <= -halfW + thickness) {\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n }\n // CW hole: TL → BL → tip\n hole.moveTo(-halfW + thickness, innerTailHalfH);\n hole.lineTo(-halfW + thickness, -innerTailHalfH);\n hole.lineTo(tipX, 0);\n }\n\n shape.holes.push(hole);\n return new THREE.ExtrudeGeometry(shape, extrudeSettings);\n}\n","/**\n * Component Picker Widget\n * @module scene/static/tools/ComponentPickerWidget\n *\n * DOM-based overlay widget for selecting component types organized by groups.\n * Used by BuildTool in add_component mode.\n * Follows the DOM overlay pattern established by ConfigPanelManager.\n */\n\nimport type { ComponentType } from 'simple-circuit-engine/core';\nimport { COMPONENT_TYPE_METADATA } from 'simple-circuit-engine/core';\nimport type { IGroupedFactoryRegistry } from '../../shared/components/GroupedFactoryRegistry';\n\n/**\n * Sentinel value representing the \"Branching Point\" pseudo-component entry.\n * When selected, BuildTool creates a branching point instead of a component.\n */\nexport const BRANCHING_POINT_SENTINEL = '__branching_point__' as const;\n\n/**\n * Union of actual component types and the branching point sentinel.\n */\nexport type PickerSelection = ComponentType | typeof BRANCHING_POINT_SENTINEL;\n\n/**\n * Persisted widget state (survives open/close cycles within a session).\n */\nexport interface ComponentPickerState {\n selectedGroupId: string;\n selectedItem: PickerSelection | null;\n widgetWidth: number;\n widgetHeight: number;\n}\n\n/** Group id where the Branching Point entry is prepended */\nconst BRANCHING_POINT_GROUP = 'basic';\n\n/** Default widget dimensions */\nconst DEFAULT_WIDTH = 180;\nconst DEFAULT_HEIGHT = 300;\n\n/** Viewport positioning constants (matching ConfigPanelManager) */\nconst OFFSET_X = -240;\nconst OFFSET_Y = -150;\nconst VIEWPORT_PADDING = 10;\n\n/**\n * DOM overlay widget for selecting components from grouped registry.\n *\n * Features:\n * - Group dropdown for filtering component types\n * - Scrollable item list with selection highlight\n * - Draggable header bar\n * - Resizable via CSS resize\n * - State persistence across open/close (group, selection, size)\n */\nexport class ComponentPickerWidget {\n // DOM elements\n private container: HTMLDivElement | null = null;\n private groupDropdown: HTMLSelectElement | null = null;\n private itemList: HTMLDivElement | null = null;\n\n // Persisted state\n private state: ComponentPickerState;\n\n // Callbacks\n private readonly onSelectionChange: (selection: PickerSelection | null) => void;\n private readonly onClose: () => void;\n\n // Event handler references for cleanup\n private escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n\n // Drag state\n private dragOffset: { x: number; y: number } | null = null;\n private dragMoveHandler: ((e: MouseEvent) => void) | null = null;\n private dragEndHandler: ((e: MouseEvent) => void) | null = null;\n\n /**\n * @param registry - Grouped factory registry providing groups and component types\n * @param onSelectionChange - Called when user selects or deselects an item\n * @param onClose - Called when user closes the widget (close button or Escape)\n */\n constructor(\n private readonly registry: IGroupedFactoryRegistry,\n onSelectionChange: (selection: PickerSelection | null) => void,\n onClose: () => void\n ) {\n this.onSelectionChange = onSelectionChange;\n this.onClose = onClose;\n\n // Initialize state with first available group\n const groups = registry.getGroups();\n const firstGroup = groups[0];\n this.state = {\n selectedGroupId: firstGroup ? firstGroup.id : '',\n selectedItem: null,\n widgetWidth: DEFAULT_WIDTH,\n widgetHeight: DEFAULT_HEIGHT,\n };\n }\n\n /** Whether the widget is currently open and visible */\n get isOpen(): boolean {\n return this.container !== null;\n }\n\n /** The currently selected item (persists across open/close) */\n get currentSelection(): PickerSelection | null {\n return this.state.selectedItem;\n }\n\n /**\n * Open the widget at the given screen position.\n * If already open, repositions to the new location.\n *\n * @param screenPosition - Screen coordinates (typically from mouse event)\n */\n open(screenPosition: { x: number; y: number }): void {\n if (this.container) {\n this.positionContainer(screenPosition);\n return;\n }\n\n this.createDOM();\n this.positionContainer(screenPosition);\n this.renderItemList();\n this.registerEventListeners();\n }\n\n /**\n * Close the widget and remove DOM.\n * Preserves state (group, selection, size) for next open.\n */\n close(): void {\n if (!this.container) return;\n\n // Save current size before removing\n this.state.widgetWidth = this.container.offsetWidth;\n this.state.widgetHeight = this.container.offsetHeight;\n\n this.removeEventListeners();\n document.body.removeChild(this.container);\n this.container = null;\n this.groupDropdown = null;\n this.itemList = null;\n }\n\n /**\n * Full cleanup including state reset.\n */\n dispose(): void {\n this.close();\n }\n\n // ========================================================================\n // DOM Creation\n // ========================================================================\n\n private createDOM(): void {\n // Container\n this.container = document.createElement('div');\n Object.assign(this.container.style, {\n position: 'absolute',\n zIndex: '1000',\n width: `${this.state.widgetWidth}px`,\n height: `${this.state.widgetHeight}px`,\n minWidth: '140px',\n minHeight: '120px',\n maxHeight: '500px',\n background: '#2a2a2a',\n color: '#eee',\n borderRadius: '6px',\n fontFamily: 'sans-serif',\n fontSize: '13px',\n boxShadow: '0 4px 16px rgba(0,0,0,0.4)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n resize: 'both',\n });\n\n // Header bar (draggable)\n const header = document.createElement('div');\n Object.assign(header.style, {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '6px 8px',\n background: '#333',\n cursor: 'grab',\n userSelect: 'none',\n borderRadius: '6px 6px 0 0',\n flexShrink: '0',\n });\n\n const title = document.createElement('span');\n title.textContent = 'Components';\n Object.assign(title.style, {\n fontWeight: 'bold',\n fontSize: '13px',\n });\n\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '\\u00D7'; // multiplication sign (x)\n Object.assign(closeBtn.style, {\n background: 'none',\n border: 'none',\n color: '#aaa',\n fontSize: '18px',\n cursor: 'pointer',\n padding: '0 4px',\n lineHeight: '1',\n });\n closeBtn.addEventListener('mouseenter', () => {\n closeBtn.style.color = '#fff';\n });\n closeBtn.addEventListener('mouseleave', () => {\n closeBtn.style.color = '#aaa';\n });\n closeBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.onClose();\n });\n\n header.appendChild(title);\n header.appendChild(closeBtn);\n\n // Make header draggable\n header.addEventListener('mousedown', (e) => {\n if (e.target === closeBtn) return;\n this.startDrag(e);\n });\n\n // Group dropdown\n this.groupDropdown = document.createElement('select');\n Object.assign(this.groupDropdown.style, {\n margin: '6px 8px',\n padding: '4px 6px',\n background: '#444',\n color: '#eee',\n border: '1px solid #555',\n borderRadius: '4px',\n fontSize: '12px',\n flexShrink: '0',\n cursor: 'pointer',\n });\n\n let groups = this.registry.getGroups();\n // Exception rule : if groups doesn't include a basic group\n // an empty one is created to get access to branching points\n if (groups.filter((g) => g.id === BRANCHING_POINT_GROUP).length < 1) {\n groups = [{ id: BRANCHING_POINT_GROUP, label: BRANCHING_POINT_GROUP }, ...groups];\n }\n\n for (const group of groups) {\n const option = document.createElement('option');\n option.value = group.id;\n option.textContent = group.label;\n this.groupDropdown.appendChild(option);\n }\n this.groupDropdown.value = this.state.selectedGroupId;\n this.groupDropdown.addEventListener('change', () => {\n this.state.selectedGroupId = this.groupDropdown!.value;\n // Clear selection when switching groups\n if (this.state.selectedItem !== null) {\n this.state.selectedItem = null;\n this.onSelectionChange(null);\n }\n this.renderItemList();\n });\n\n // Item list container (scrollable)\n this.itemList = document.createElement('div');\n Object.assign(this.itemList.style, {\n flex: '1',\n overflowY: 'auto',\n padding: '0 4px 4px 4px',\n });\n\n // Assemble\n this.container.appendChild(header);\n this.container.appendChild(this.groupDropdown);\n this.container.appendChild(this.itemList);\n document.body.appendChild(this.container);\n }\n\n // ========================================================================\n // Item List Rendering\n // ========================================================================\n\n private renderItemList(): void {\n if (!this.itemList) return;\n this.itemList.innerHTML = '';\n\n const groupId = this.state.selectedGroupId;\n const types = this.registry.getRegisteredTypes(groupId);\n\n // Prepend Branching Point entry in the basic group\n if (groupId === BRANCHING_POINT_GROUP) {\n this.itemList.appendChild(\n this.createItemElement('Branching Point', BRANCHING_POINT_SENTINEL)\n );\n }\n\n for (const type of types) {\n const metadata = COMPONENT_TYPE_METADATA[type];\n const label = metadata ? metadata.name : type;\n this.itemList.appendChild(this.createItemElement(label, type));\n }\n }\n\n private createItemElement(label: string, value: PickerSelection): HTMLDivElement {\n const item = document.createElement('div');\n item.textContent = label;\n const isSelected = this.state.selectedItem === value;\n\n Object.assign(item.style, {\n padding: '6px 8px',\n margin: '2px 0',\n borderRadius: '4px',\n cursor: 'pointer',\n background: isSelected ? '#4a6fa5' : 'transparent',\n transition: 'background 0.15s',\n });\n\n item.addEventListener('mouseenter', () => {\n if (this.state.selectedItem !== value) {\n item.style.background = '#3a3a3a';\n }\n });\n item.addEventListener('mouseleave', () => {\n item.style.background = this.state.selectedItem === value ? '#4a6fa5' : 'transparent';\n });\n item.addEventListener('click', (e) => {\n e.stopPropagation();\n this.selectItem(value);\n });\n\n return item;\n }\n\n private selectItem(value: PickerSelection): void {\n // Toggle: clicking the already-selected item deselects it\n const newValue = this.state.selectedItem === value ? null : value;\n this.state.selectedItem = newValue;\n this.renderItemList(); // Re-render to update highlight\n this.onSelectionChange(newValue);\n }\n\n // ========================================================================\n // Positioning (ConfigPanelManager pattern)\n // ========================================================================\n\n private positionContainer(screenPosition: { x: number; y: number }): void {\n if (!this.container) return;\n\n const panelWidth = this.state.widgetWidth;\n const panelHeight = this.state.widgetHeight;\n\n let left = screenPosition.x + OFFSET_X;\n let top = screenPosition.y + OFFSET_Y;\n\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // If would overflow, shift\n if (left + panelWidth > viewportWidth - VIEWPORT_PADDING) {\n left = screenPosition.x - panelWidth - OFFSET_X;\n } else if (left < viewportWidth + VIEWPORT_PADDING) {\n left = screenPosition.x + OFFSET_X;\n }\n\n // Clamp left\n if (left < VIEWPORT_PADDING) {\n left = VIEWPORT_PADDING;\n }\n // Clamp top\n if (top < VIEWPORT_PADDING) {\n top = VIEWPORT_PADDING;\n } else if (top + panelHeight > viewportHeight - VIEWPORT_PADDING) {\n top = viewportHeight - panelHeight - VIEWPORT_PADDING;\n }\n\n this.container.style.left = `${left}px`;\n this.container.style.top = `${top}px`;\n }\n\n // ========================================================================\n // Dragging\n // ========================================================================\n\n private startDrag(e: MouseEvent): void {\n if (!this.container) return;\n e.preventDefault();\n\n this.dragOffset = {\n x: e.clientX - this.container.offsetLeft,\n y: e.clientY - this.container.offsetTop,\n };\n\n this.container.style.cursor = 'grabbing';\n\n this.dragMoveHandler = (ev: MouseEvent) => this.onDragMove(ev);\n this.dragEndHandler = () => this.endDrag();\n document.addEventListener('mousemove', this.dragMoveHandler);\n document.addEventListener('mouseup', this.dragEndHandler);\n }\n\n private onDragMove(e: MouseEvent): void {\n if (!this.container || !this.dragOffset) return;\n\n let left = e.clientX - this.dragOffset.x;\n let top = e.clientY - this.dragOffset.y;\n\n // Clamp to viewport\n const maxLeft = window.innerWidth - this.container.offsetWidth - VIEWPORT_PADDING;\n const maxTop = window.innerHeight - this.container.offsetHeight - VIEWPORT_PADDING;\n left = Math.max(VIEWPORT_PADDING, Math.min(left, maxLeft));\n top = Math.max(VIEWPORT_PADDING, Math.min(top, maxTop));\n\n this.container.style.left = `${left}px`;\n this.container.style.top = `${top}px`;\n }\n\n private endDrag(): void {\n if (this.container) {\n this.container.style.cursor = '';\n }\n this.dragOffset = null;\n\n if (this.dragMoveHandler) {\n document.removeEventListener('mousemove', this.dragMoveHandler);\n this.dragMoveHandler = null;\n }\n if (this.dragEndHandler) {\n document.removeEventListener('mouseup', this.dragEndHandler);\n this.dragEndHandler = null;\n }\n }\n\n // ========================================================================\n // Event Listeners\n // ========================================================================\n\n private registerEventListeners(): void {\n this.escapeHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.onClose();\n }\n };\n document.addEventListener('keydown', this.escapeHandler);\n }\n\n private removeEventListeners(): void {\n this.endDrag();\n\n if (this.escapeHandler) {\n document.removeEventListener('keydown', this.escapeHandler);\n this.escapeHandler = null;\n }\n }\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 * - Component placement & addition (add_component mode with picker widget)\n *\n * Replaces old: PositionTool, WireTool, DeleteTool, BranchingPointTool, AddComponentTool\n */\n\nimport * as THREE from 'three';\nimport { Euler } from 'three';\nimport { Line2 } from 'three/examples/jsm/lines/Line2.js';\nimport {\n type UUID,\n type ComponentType,\n ENodeSourceType,\n ENodeType,\n ENode,\n Position,\n Rotation,\n Component,\n} 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 { IGroupedFactoryRegistry } from '../../shared/components/GroupedFactoryRegistry';\nimport type { CircuitController } from '../CircuitController';\nimport {\n gridToWorldRotation,\n nearestWorldSnapPosition,\n worldToGridPosition,\n} from '../../shared/utils/GeometryUtils';\nimport {\n ComponentPickerWidget,\n BRANCHING_POINT_SENTINEL,\n type PickerSelection,\n} from './ComponentPickerWidget';\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 * idle → add_component (double-click empty space)\n * add_component → idle (Escape, close widget)\n * {any active mode} → idle (pointerup, Escape, or operation complete)\n */\ntype BuildToolMode =\n | 'idle'\n | 'wire_creation'\n | 'wire_drag'\n | 'component_drag'\n | 'bp_drag'\n | 'add_component';\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 private lastOperationCompletedTs: number = 0;\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 // Component picker widget (add_component mode)\n private pickerWidget: ComponentPickerWidget | null = null;\n\n // Ghost preview for add_component mode\n private ghostPreview: THREE.Group | null = null;\n private hasOverlap: boolean = false;\n\n // Currently selected item in the picker (persists across mode entries)\n private pickerSelection: PickerSelection | 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 // Initialize component picker widget if registry supports groups\n const registry = controller.factoryRegistry;\n if ('getGroups' in registry && typeof (registry as any).getGroups === 'function') {\n this.pickerWidget = new ComponentPickerWidget(\n registry as unknown as IGroupedFactoryRegistry,\n (selection) => this.onPickerSelectionChange(selection),\n () => this.exitAddComponentMode()\n );\n }\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 // Clean up add_component mode resources\n this.disposeGhostPreview();\n this.pickerWidget?.close();\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 this.hasOverlap = false;\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 } else if (this.mode === 'add_component') {\n this.exitAddComponentMode();\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 add_component mode\n if (this.mode === 'add_component') {\n if (hoveredElement && hoveredElement.type === 'component') return 'pointer';\n if (this.hasOverlap) return 'not-allowed';\n return this.pickerSelection ? 'crosshair' : 'default';\n }\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 // Add component ghost preview\n if (this.mode === 'add_component' && this.ghostPreview) {\n previews.push(this.ghostPreview);\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 } else if (this.mode === 'add_component') {\n // In add_component mode, clicking on empty space places the selected item\n if (!hoveredElement && this.pickerSelection) {\n if (this.hasOverlap) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: 'add_component',\n errorMessage: 'Cannot place component: position occupied',\n });\n return;\n }\n this.placeSelectedItem();\n }\n return;\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 // add_component mode manages its own gridPositionMove listener lifecycle\n if (this.mode === 'add_component') return;\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 case 'add_component':\n this.updateAddComponentPreview(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 === 'add_component') {\n this.exitAddComponentMode();\n } else 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 if (event.ctrlKey || event.metaKey) return; // prevent rotating while ctrl hold\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 - open component picker widget\n // Suppress if a drag/wire operation just completed (avoids false dblclick after quick drag-release)\n if (Date.now() - this.lastOperationCompletedTs < 400) return;\n if (this.pickerWidget && this.mode === 'idle') {\n this.enterAddComponentMode(event);\n } else if (!this.pickerWidget) {\n // Fallback: create standalone branching point if no grouped registry\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 /**\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 this._controller.autoAdjustCircuitGridSize();\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.lastOperationCompletedTs = Date.now();\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 this.lastOperationCompletedTs = Date.now();\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.autoAdjustCircuitGridSize();\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.autoAdjustCircuitGridSize();\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 this.lastOperationCompletedTs = Date.now();\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.autoAdjustCircuitGridSize();\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 this.lastOperationCompletedTs = Date.now();\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 this._controller.autoAdjustCircuitGridSize();\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 // Add Component Mode\n // ========================================================================\n\n /**\n * Enter add_component mode: open the picker widget and listen for cursor movement\n * @param event - Mouse event (used for widget positioning)\n */\n private enterAddComponentMode(event: MouseEvent): void {\n if (!this.pickerWidget) return;\n\n this.mode = 'add_component';\n const screenPos = { x: event.clientX, y: event.clientY };\n this.pickerWidget.open(screenPos);\n\n // Listen for cursor movement for ghost preview\n this._controller.on('gridPositionMove', this.handleGridPositionMove);\n\n // If there was a previous selection, recreate the ghost\n if (this.pickerWidget.currentSelection) {\n this.pickerSelection = this.pickerWidget.currentSelection;\n this.createGhostPreview(this.pickerSelection);\n }\n\n this._controller.emit('toolOperationStarted', {\n toolType: this.type,\n mode: 'add_component',\n operationData: {},\n });\n }\n\n /**\n * Exit add_component mode: close widget, dispose ghost, return to idle\n */\n private exitAddComponentMode(): void {\n if (this.mode !== 'add_component') return;\n\n this.disposeGhostPreview();\n this.pickerWidget?.close();\n this._controller.off('gridPositionMove', this.handleGridPositionMove);\n this.hasOverlap = false;\n\n this._controller.emit('toolOperationCancelled', {\n toolType: this.type,\n mode: 'add_component',\n });\n\n this.mode = 'idle';\n }\n\n /**\n * Called when user selects or deselects an item in the picker widget\n */\n private onPickerSelectionChange(selection: PickerSelection | null): void {\n this.pickerSelection = selection;\n this.disposeGhostPreview();\n if (selection) {\n this.createGhostPreview(selection);\n }\n }\n\n /**\n * Place the currently selected item (component or branching point) at cursor position\n */\n private placeSelectedItem(): void {\n if (!this.pickerSelection) return;\n\n const worldPosition = this._controller.cursorGroundPlanePosition();\n\n if (this.pickerSelection === BRANCHING_POINT_SENTINEL) {\n const enodeId = this.createStandaloneBranchingPoint(worldPosition);\n if (enodeId) {\n this._controller.getSelectionManager().selectOne('enode', enodeId, { componentId: null });\n }\n // Recreate ghost for next placement\n this.disposeGhostPreview();\n this.createGhostPreview(this.pickerSelection);\n return;\n }\n\n try {\n const component = this._controller.addComponent(this.pickerSelection, worldPosition, null);\n this._controller.autoAdjustCircuitGridSize();\n this._controller.emit('toolOperationCompleted', {\n toolType: this.type,\n mode: 'add_component',\n operationData: {\n componentId: component.id,\n componentType: this.pickerSelection,\n position: worldPosition.clone(),\n },\n changedData: { addedComponents: [component.id] },\n });\n // Recreate ghost for next placement\n this.disposeGhostPreview();\n this.createGhostPreview(this.pickerSelection);\n } catch (error) {\n this._controller.emit('toolValidationError', {\n toolType: this.type,\n mode: 'add_component',\n errorMessage: `Failed to place component: ${(error as Error).message}`,\n });\n }\n }\n\n /**\n * Update ghost preview position and overlap check during add_component mode\n */\n private updateAddComponentPreview(worldPosition: THREE.Vector3): void {\n if (!this.ghostPreview) return;\n\n const snappedPosition = new THREE.Vector3(\n Math.round(worldPosition.x),\n 0,\n Math.round(worldPosition.z)\n );\n this.ghostPreview.position.copy(snappedPosition);\n\n // Check for overlap\n const previousOverlap = this.hasOverlap;\n this.hasOverlap = this.checkGhostOverlap();\n\n if (this.hasOverlap && !previousOverlap) {\n this.applyInvalidEffect(this.ghostPreview);\n } else if (!this.hasOverlap && previousOverlap) {\n this.removeInvalidEffect(this.ghostPreview);\n }\n }\n\n // ========================================================================\n // Ghost Preview\n // ========================================================================\n\n /**\n * Create ghost preview for the selected item\n * @param selection - Component type or branching point sentinel\n */\n private createGhostPreview(selection: PickerSelection): void {\n this.disposeGhostPreview();\n\n try {\n let visual: THREE.Object3D;\n\n if (selection === BRANCHING_POINT_SENTINEL) {\n // Create a branching point preview using the factory\n const tempEnode = new ENode(\n ENodeType.BranchingPoint,\n undefined,\n undefined,\n new Position(0, 0)\n );\n visual = this._controller.branchingPointVisualFactory.createVisual(tempEnode);\n } else {\n const factory = this._controller.factoryRegistry.get(selection);\n const tempComponent = new Component(\n selection,\n new Position(0, 0),\n new Rotation(0),\n [] // Empty pins array for preview\n );\n visual = factory.createVisual(tempComponent, this._controller.visualContext);\n visual.rotation.set(0, factory.defaultRotation(), 0);\n }\n\n if (!(visual instanceof THREE.Group)) {\n console.warn(`Factory returned non-Group object for ${selection}`);\n return;\n }\n\n // Mark as preview\n visual.userData.preview = true;\n visual.traverse((child) => {\n child.userData.preview = true;\n });\n\n this.ghostPreview = visual;\n this.applyGhostEffect(this.ghostPreview);\n\n // Position at current cursor\n const cursorPos = this._controller.cursorGroundPlanePosition();\n this.ghostPreview.position.set(Math.round(cursorPos.x), 0, Math.round(cursorPos.z));\n\n this._controller.getScene().add(this.ghostPreview);\n } catch (error) {\n console.warn(`Failed to create ghost preview for ${selection}:`, error);\n this.ghostPreview = null;\n }\n }\n\n /**\n * Dispose ghost preview and cleanup resources\n */\n private disposeGhostPreview(): void {\n if (!this.ghostPreview) return;\n\n this._controller.getScene().remove(this.ghostPreview);\n this.ghostPreview.traverse((child) => {\n if (child instanceof THREE.Mesh) {\n if (child.geometry) child.geometry.dispose();\n if (Array.isArray(child.material)) {\n child.material.forEach((mat) => mat.dispose());\n } else if (child.material) {\n child.material.dispose();\n }\n }\n });\n this.ghostPreview = null;\n this.hasOverlap = false;\n }\n\n /**\n * Apply semi-transparent ghost effect to preview object\n */\n private applyGhostEffect(object: THREE.Object3D): void {\n object.traverse((child) => {\n if (child instanceof THREE.Mesh) {\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 * Check if ghost preview overlaps with existing components\n */\n private checkGhostOverlap(): boolean {\n if (!this.ghostPreview) return false;\n\n // Branching points don't need overlap detection\n if (this.pickerSelection === BRANCHING_POINT_SENTINEL) return false;\n\n const previewBox = new THREE.Box3().setFromObject(this.ghostPreview);\n const componentObjects = this._controller.componentObject3Ds;\n\n for (const [_id, otherGroup] of componentObjects) {\n // to make this rule not too strict we signal overlap only if ghost box contains the center of other component box\n if(previewBox.containsPoint(otherGroup.position)){\n return true;\n }\n }\n return false;\n }\n\n /**\n * Apply red emissive to indicate invalid placement\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 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 * Remove red emissive invalid placement effect\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 if (child.material instanceof THREE.MeshStandardMaterial) {\n child.material.emissive.setHex(0x000000);\n child.material.emissiveIntensity = 0;\n }\n }\n });\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();\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();\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();\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 {\n computeDivisionsForSize,\n worldToGridPosition,\n worldToGridRotation,\n} 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\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 circuit.resolveTransitionSpan(component);\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.DoubleThrowSwitch:\n config.set('initialState', config.get('initialState') === 'input1' ? 'input2' : 'input1');\n this.saveEditComponentConfig(component.id, config);\n return { hasChanged: true, component: component };\n default:\n if (!config.has('activationLogic')) {\n return { hasChanged: false, component: component };\n }\n config.set(\n 'activationLogic',\n config.get('activationLogic') === 'positive' ? 'negative' : 'positive'\n );\n circuit.resolveTransitionSpan(component);\n this.saveEditComponentConfig(component.id, config);\n return { hasChanged: true, 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\n/**\n * returns default complete mapControlsOptions or an autocompleted partial mapControlOptions\n * @param options\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: 200,\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\n/**\n * returns default complete controllerOptions or an autocompleted partial controllerOptions\n * @param options\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 simulationSpeed: 3,\n simulationAutoPlay: false,\n };\n\n if (!options) return defaultOptions;\n options.mapControls = mapControlsOptions(options.mapControls);\n return { ...defaultOptions, ...options };\n}\n\n/**\n * returns default complete engineOptions or and autoCompleted partial engineOptions\n * @param options\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, type 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, VisualContext,\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 // @Memoize(...{\n // expiring: undefined,\n // hashFunction: (this._circuit) => this._circuit,\n // tags: undefined\n // })\n get visualContext(): VisualContext {\n return {\n getENode: (id: UUID) => this._circuit?.getENode(id)\n }\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\n if (!!this._circuit) {\n // Clear all existing visuals\n this._removeAllVisuals();\n const oldCircuitName = (this._circuit.metadata && this._circuit.metadata.options)?\n this._circuit.metadata.options.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 nameOrDefault = (circuit.metadata && circuit.metadata.options)?\n circuit.metadata.options.name: 'Unnamed Circuit';\n const options = this._options || controllerOptions();\n // Perform full update with new circuit\n this._circuit = circuit;\n this._scene!.name = nameOrDefault;\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: nameOrDefault});\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, default false\n */\n cursorGroundPlanePosition(bound: boolean = false): 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 ConfigPanelWidget {\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(component.config);\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\n for (const field of formDef.fields) {\n let controller: ReturnType<GUI['add']> | null = null;\n\n switch (field.type) {\n case 'boolean':\n controller = this.gui\n .add(this.formDataObject, field.key)\n .name(field.label)\n .onChange((value: any) => this.onValueChange(field.key, value, component, factory));\n break;\n\n case 'dropdown':\n if (field.options) {\n controller = this.gui\n .add(this.formDataObject, field.key, field.options)\n .name(field.label)\n .onChange((value: any) => this.onValueChange(field.key, value, component, factory));\n }\n break;\n\n case 'number':\n controller = this.gui\n .add(this.formDataObject, field.key)\n .name(field.label)\n .onChange((value: any) => this.onValueChange(field.key, value, 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 controller = this.gui\n .add(this.formDataObject, field.key)\n .name(field.label)\n .onChange((value: any) => this.onValueChange(field.key, value, component, factory));\n break;\n\n case 'color':\n controller = this.gui\n .addColor(this.formDataObject, field.key)\n .name(field.label)\n .onChange((value: any) => this.onValueChange(field.key, value, component, factory));\n break;\n }\n\n if (controller && field.disabled) {\n controller.disable(true);\n }\n }\n }\n\n /**\n * Handle value change in the config form\n * Maps form data back to core config and updates the component.\n * When defaultLogicFamily or activationLogic changes, rebuilds the GUI to reflect\n * updated disabled states and computed transitionSpan values.\n *\n * @param changedKey - The key of the field that changed\n * @param _value - The new value\n * @param component - Component being edited\n * @param factory - Visual factory for the component\n */\n private onValueChange(changedKey: string, _value: any, 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 // Rebuild GUI when defaultLogicFamily or activationLogic changes to update disabled states\n if (changedKey === 'defaultLogicFamily' || changedKey === 'activationLogic') {\n this.rebuildGui(component, factory);\n }\n }\n\n /**\n * Rebuild the GUI in place, re-reading the updated component config.\n * Used after interdependent field changes (defaultLogicFamily, activationLogic).\n */\n private rebuildGui(component: any, factory: any): void {\n if (!this.gui || !this.container) return;\n\n // Destroy existing GUI\n this.gui.destroy();\n this.gui = null;\n\n // Re-read updated config from the component (already updated by editComponentConfig)\n const formDef = factory.getConfigFormDefinition(component.config);\n if (!formDef) return;\n\n this.buildGui(formDef, component, factory);\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 {\n Component,\n Wire,\n ENode,\n UUID,\n ComponentType,\n ENodeSourceType,\n Circuit,\n} from 'simple-circuit-engine/core';\nimport { ENodeType } from 'simple-circuit-engine/core';\nimport type { IFactoryRegistry } from '../shared/components/ComponentVisualFactory';\nimport type {\n ToolType,\n SelectionData,\n SharedResources,\n ControllerOptions,\n IEditingTool,\n} from '../shared/types';\nimport {\n createGridHelper,\n gridToWorldPosition,\n gridToWorldRotation,\n} from '../shared/utils/GeometryUtils';\nimport { BuildTool } from './tools/BuildTool';\nimport { MultiSelectTool } from './tools/MultiSelectTool';\nimport { SelectionManager } from '../shared/SelectionManager';\nimport { CircuitWriter } from './CircuitWriter';\nimport { AbstractCircuitController } from '../shared/AbstractCircuitController';\nimport { ConfigPanelWidget } from './tools/ConfigPanelWidget';\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: ConfigPanelWidget | 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 // Initialize tools\n this._initializeTools();\n // Initialize Selection Manager\n this._initializeSelectionManager();\n // Initialize Config Panel Manager\n this._initializeConfigPanelManager();\n\n this._initialized = true; // flag must be set before calling setActiveTool\n // standalone mode -> Controller active\n if (!this._sharedResources) {\n this.setActive(true);\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 ConfigPanelWidget(\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 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('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, this.visualContext);\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 this.autoAdjustCircuitGridSize();\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 this.autoAdjustCircuitGridSize();\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, if left null the default componentType rotation is applied\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 | null,\n config?: Map<string, string> | undefined,\n pinSources?: Array<ENodeSourceType | undefined | null> | undefined\n ): Component {\n if (!rotation) {\n const factory = this.factoryRegistry.get(type);\n const defaultRotation = factory ? factory.defaultRotation() : 0;\n rotation = new THREE.Euler(0, defaultRotation, 0);\n }\n\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 this.autoAdjustCircuitGridSize();\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 this.autoAdjustCircuitGridSize();\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 {\n type Component,\n type Wire,\n type ENode,\n type Circuit,\n type IUserCommand,\n TRANSITION_DEFAULTS, SIMULATION_SPEED\n} from 'simple-circuit-engine/core';\nimport {\n ENodeType,\n ComponentType,\n CircuitRunner,\n BehaviorRegistry,\n} from 'simple-circuit-engine/core';\nimport type { IFactoryRegistry } from '../shared/components/ComponentVisualFactory';\nimport type { SharedResources, HoveredElement, ControllerOptions } 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 _autoPlay = false;\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 * @param options - Controller options passed to initialize()\n */\n protected onInitialize(options?: ControllerOptions) {\n if (options) {\n if (options.simulationSpeed) this.simulationSpeed = options.simulationSpeed;\n if (typeof options.simulationAutoPlay == 'boolean')\n this._autoPlay = options.simulationAutoPlay;\n }\n // Register click handler for component (switches) interaction\n this._clickHandler = this._handleClick.bind(this);\n this._container!.addEventListener('click', this._clickHandler);\n\n // standalone mode -> Controller active\n if (!this._sharedResources) {\n this.setActive(true);\n }\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 // update graphics\n this._fullUpdate();\n // if autoplay launch !\n if (this._autoPlay) this.play();\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 if (!this._active) return; // nothing more to do if not active\n // if active launch the thing\n this._runner = new CircuitRunner(circuit, this._behaviorRegistry);\n // update graphics\n this._fullUpdate();\n // if autoplay launch !\n if (this._autoPlay) this.play();\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.DoubleThrowSwitch:\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: IUserCommand = {\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, this.visualContext);\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 const startupMode = this._mode as EngineMode;\n this.emit('modeChanged', { mode: startupMode });\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(`Factory must be a an object with createVisual method for type: ${type}`);\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, type ComponentType, type ComponentState, ENode} 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, VisualContext } from '../types';\nimport type {Direction2D} from \"../utils/GeometryUtils\";\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, context?: VisualContext): 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 * @returns nominal rotation along the Y axis when component added (angle in radian)\n */\n defaultRotation(): number;\n\n /**\n * Create the Three.js visual representation for a component\n *\n * @param component - The circuit component to visualize\n * @param context - Optional visual context providing access to ENode data\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, context: VisualContext): 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 * @param config - Optional current component config to compute field states (e.g., disabled)\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 * When config is provided, implementations may use it to set field.disabled\n * based on interdependencies (e.g., transitionSpan disabled when defaultLogicFamily != Sandbox).\n */\n getConfigFormDefinition(config?: Map<string, string>): 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, context?: VisualContext): 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 defaultRotation() {\n return 0;\n }\n\n /**\n * Create the Three.js visual representation for a component\n * Must be implemented by subclasses\n */\n abstract createVisual(component: Component, context: VisualContext): 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 * @private\n */\n private pointPinGroupToward(group: THREE.Group, direction: Direction2D){\n switch(direction) {\n case 'right':\n group.rotateZ(-Math.PI / 2);\n group.rotateY(Math.PI);\n break;\n case 'bottom':\n group.rotateX(Math.PI / 2);\n break;\n case 'left':\n group.rotateZ(Math.PI / 2);\n group.rotateY(Math.PI);\n break;\n case 'top':\n group.rotateX(-Math.PI / 2);\n break;\n }\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 node - ENode to create as visual pin\n * @param pointsTo - rotate pin to make it point the wanted direction\n * @param visualRotation - if set rotate the visual of the pin to adjust display without affecting hitbox\n * @returns THREE.Group configured as pin group\n */\n protected createPinGroup(\n node: ENode,\n pointsTo: Direction2D = 'right',\n visualRotation: THREE.Euler | null = null\n ): THREE.Group {\n if (!node.component){\n throw new Error('This method only manage components eNodes (pins)');\n }\n\n // pins with this subtype will be considered locked (not possible to change their source type)\n const lockedSubtypes = ['mainVcc', 'vcc', 'mainGnd', 'gnd', 'logicOutput'];\n // pins with this subtype will be represented smaller (not intended to be wired on anything so they're just a reminder for the user)\n const smallSubtypes = ['vcc', 'gnd'];\n\n const userInfos = {\n componentId: node.component,\n enodeId: node.id,\n label: node.pinLabel,\n subtype: node.subtype,\n lockedSourceType: lockedSubtypes.includes(node.subtype)\n };\n\n const pinGroup = new THREE.Group();\n pinGroup.userData = {...userInfos, type: 'enodeGroup', sourceType: node.source || null};\n // default radius\n let hitboxRadius = 0.9;\n let visualRadius = 0.3;\n // since those pins won't be used for wiring they can be smaller\n if(smallSubtypes.includes(node.subtype)){\n hitboxRadius = 0.25;\n visualRadius = 0.2;\n }\n\n // Hitbox (hemisphere, raycastable)\n const hitboxGeom = new THREE.SphereGeometry(hitboxRadius, 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 = {...userInfos, type: 'enodeHitbox'};\n hitbox.layers.set(HitboxLayers.ENODE);\n pinGroup.add(hitbox);\n\n // Visual sphere\n const visual = new THREE.Mesh(\n new THREE.SphereGeometry(visualRadius, 16, 8, 0, Math.PI * 2, 0, Math.PI / 2),\n new THREE.MeshStandardMaterial({\n color: this.pinColorForSourceType(node.source || null),\n emissive: this.pinColorForSourceType(node.source || null),\n emissiveIntensity: 0,\n })\n );\n visual.userData = {\n ...userInfos,\n type: 'enode',\n sourceType: node.source || null,\n radius: visualRadius\n };\n pinGroup.add(visual);\n if (!!visualRotation) {\n visual.setRotationFromEuler(visualRotation);\n }\n\n this.pointPinGroupToward(pinGroup, pointsTo);\n return pinGroup;\n }\n\n /**\n * Utility to create semi spheres visually closing pins\n * @param pinGroup\n * @param material\n * @protected\n */\n protected createPinCounterpart(\n pinGroup: THREE.Group,\n material: THREE.MeshStandardMaterial\n ): THREE.Mesh | null {\n\n const pinVisual = this.findPinVisualFromGroup(pinGroup);\n if(!pinVisual){\n return null;\n }\n\n const visual = new THREE.Mesh(\n new THREE.SphereGeometry(pinVisual.userData.radius, 16, 8,\n 0, Math.PI * 2, 0, Math.PI / 2),\n material\n );\n visual.userData = {\n type: 'component',\n componentId: pinVisual.userData.componentId,\n part: 'pinCounterpart'\n }\n visual.position.copy(pinGroup.position);\n\n const pinVisualRotation = pinVisual.rotation.clone();\n\n visual.rotation.copy(new THREE.Euler(\n -pinGroup.rotation.x,\n -pinGroup.rotation.y,\n -pinGroup.rotation.z,\n pinGroup.rotation.order));\n visual.rotateX(-pinVisualRotation.x);\n visual.rotateY(-pinVisualRotation.y);\n visual.rotateZ(pinVisualRotation.z);\n\n return visual;\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 * fin pin inner visual from within its pin group\n * @param pinGroup\n */\n findPinVisualFromGroup(pinGroup: THREE.Group): THREE.Mesh | null {\n let pinVisual: THREE.Mesh | null;\n pinGroup.traverse((child) => {\n if (child.userData.type === 'enode' && child instanceof THREE.Mesh) {\n pinVisual = child;\n }\n });\n // @ts-ignore\n return pinVisual;\n }\n\n /**\n * Find pin group visual by label within a component Object3D\n * @param object3D\n * @param label\n */\n findPinVisual(object3D: THREE.Object3D, label: string): THREE.Mesh | null {\n let pinGroup: THREE.Group | null = this.findPinGroup(object3D, label);\n if (!pinGroup) {\n return null;\n }\n return this.findPinVisualFromGroup(pinGroup);\n }\n\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.2,\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 0xD4894C; // Copper 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 0xD4894C; // Copper 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 sourceType type.\n *\n * This method changes the pin's material color to reflect the sourceType type:\n * - null/undefined: copper (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 sourceType (null for no sourceType)\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 copper 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 sourceType 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 visual.userData.sourceType = sourceType;\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 }\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 source: ENodeSourceType | null =\n 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(source));\n material.emissiveIntensity = source ? 1 : 0;\n if (!source && 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(_config?: Map<string, string>): 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 * 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","/**\n * Grouped Factory Registry Implementation\n * @module scene/shared/GroupedFactoryRegistry\n *\n * Extends the basic factory registry with named group support for UI/UX-oriented\n * component palette organization. Components can only be added inside a group\n * context via addGroup(), enforcing the \"no floating components\" invariant.\n */\n\nimport type { ComponentType } from 'simple-circuit-engine/core';\nimport type { IComponentVisualFactory, IFactoryRegistry } from './ComponentVisualFactory.js';\n\n/**\n * Describes a named group of component types\n */\nexport interface ComponentGroup {\n readonly id: string;\n readonly label: string;\n}\n\n/**\n * Builder interface for adding components to a group.\n * Used as the callback parameter type in addGroup().\n *\n * @example\n * ```typescript\n * registry.addGroup('basic', 'Basic Components', (group: IComponentGroupBuilder) => {\n * group\n * .add(ComponentType.Battery, new BatteryVisualFactory())\n * .add(ComponentType.Switch, new SwitchVisualFactory());\n * });\n * ```\n */\nexport interface IComponentGroupBuilder {\n add(type: ComponentType, factory: IComponentVisualFactory): IComponentGroupBuilder;\n}\n\n/**\n * Extended registry interface with grouping support.\n *\n * Adds group management on top of the basic factory retrieval,\n * allowing client UIs to build organized component palettes.\n */\nexport interface IGroupedFactoryRegistry {\n addGroup(\n id: string,\n label: string,\n builderCallback: (group: IComponentGroupBuilder) => void\n ): IGroupedFactoryRegistry;\n get(type: ComponentType): IComponentVisualFactory;\n has(type: ComponentType): boolean;\n getFallbackFactory(): IComponentVisualFactory;\n getGroups(): ComponentGroup[];\n getGroupOf(type: ComponentType): ComponentGroup | undefined;\n getRegisteredTypes(groupId?: string): ComponentType[];\n unregister(type: ComponentType): boolean;\n}\n\n/** Internal mutable group record */\ninterface GroupRecord {\n readonly id: string;\n readonly label: string;\n types: ComponentType[];\n}\n\n/**\n * Internal builder for adding components within a named group.\n * Handles factory registration and cross-group type movement.\n */\nclass ComponentGroupBuilder implements IComponentGroupBuilder {\n constructor(\n private readonly _groupRecord: GroupRecord,\n private readonly _factories: Map<ComponentType, IComponentVisualFactory>,\n private readonly _typeToGroupId: Map<ComponentType, string>,\n private readonly _groups: Map<string, GroupRecord>\n ) {}\n\n add(type: ComponentType, factory: IComponentVisualFactory): IComponentGroupBuilder {\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 if (typeof factory !== 'object' || typeof (factory as any).createVisual !== 'function') {\n throw new TypeError(`Factory must be an object with createVisual method for type: ${type}`);\n }\n\n // If type is already registered in a different group, remove it from that group's list\n const existingGroupId = this._typeToGroupId.get(type);\n if (existingGroupId !== undefined && existingGroupId !== this._groupRecord.id) {\n const oldGroup = this._groups.get(existingGroupId);\n if (oldGroup) {\n oldGroup.types = oldGroup.types.filter((t) => t !== type);\n }\n }\n\n this._factories.set(type, factory);\n this._typeToGroupId.set(type, this._groupRecord.id);\n\n if (!this._groupRecord.types.includes(type)) {\n this._groupRecord.types.push(type);\n }\n\n return this;\n }\n}\n\n/**\n * Factory registry with named group support.\n *\n * Implements both IFactoryRegistry (backward compat) and IGroupedFactoryRegistry.\n * Components may only be registered inside a group context via addGroup().\n *\n * Group insertion order is preserved (Map maintains insertion order).\n * Duplicate group ids merge their components; the label from the first\n * registration is preserved.\n *\n * @example\n * ```typescript\n * const registry = new GroupedFactoryRegistry(new DefaultVisualFactory())\n * .addGroup('basic', 'Basic Components', group => group\n * .add(ComponentType.Battery, new BatteryVisualFactory())\n * .add(ComponentType.Switch, new SwitchVisualFactory())\n * )\n * .addGroup('outputs', 'Output Components', group => group\n * .add(ComponentType.Lightbulb, new LightbulbVisualFactory())\n * );\n *\n * registry.getGroups(); // [{ id: 'basic', ... }, { id: 'outputs', ... }]\n * registry.getGroupOf(ComponentType.Battery); // { id: 'basic', label: 'Basic Components' }\n * registry.getRegisteredTypes('basic'); // [ComponentType.Battery, ComponentType.Switch]\n * registry.get(ComponentType.Battery); // BatteryVisualFactory instance\n * ```\n */\nexport class GroupedFactoryRegistry implements IFactoryRegistry, IGroupedFactoryRegistry {\n private readonly _factories: Map<ComponentType, IComponentVisualFactory> = new Map();\n private readonly _fallbackFactory: IComponentVisualFactory;\n private readonly _groups: Map<string, GroupRecord> = new Map();\n private readonly _typeToGroupId: Map<ComponentType, string> = new Map();\n\n /**\n * Create a new grouped 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('GroupedFactoryRegistry requires a valid fallback factory');\n }\n this._fallbackFactory = fallbackFactory;\n }\n\n /**\n * Add a named group and register component factories within it.\n *\n * If a group with the same id already exists, the new components are merged\n * into it and the original label is preserved.\n *\n * @param id - Unique group identifier\n * @param label - Human-readable group display name\n * @param builderCallback - Callback receiving a builder for adding components\n * @throws {TypeError} If id or label is empty/whitespace\n * @returns this (for chaining)\n */\n addGroup(\n id: string,\n label: string,\n builderCallback: (group: IComponentGroupBuilder) => void\n ): this {\n if (typeof id !== 'string' || id.trim() === '') {\n throw new TypeError('Group id must be a non-empty string');\n }\n if (typeof label !== 'string' || label.trim() === '') {\n throw new TypeError('Group label must be a non-empty string');\n }\n\n let groupRecord = this._groups.get(id);\n if (!groupRecord) {\n groupRecord = { id, label, types: [] };\n this._groups.set(id, groupRecord);\n }\n // If group already exists: merge components, label preserved from first registration\n\n const builder = new ComponentGroupBuilder(\n groupRecord,\n this._factories,\n this._typeToGroupId,\n this._groups\n );\n builderCallback(builder);\n\n return this;\n }\n\n /**\n * Retrieve the factory for a component type.\n *\n * @returns Factory, or the fallback factory if type not registered.\n * Never returns null or undefined.\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 * @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 * Get all defined groups in insertion order.\n *\n * @returns New array of ComponentGroup objects (safe to mutate)\n */\n getGroups(): ComponentGroup[] {\n return Array.from(this._groups.values()).map((g) => ({ id: g.id, label: g.label }));\n }\n\n /**\n * Get the group a component type belongs to.\n *\n * @param type - Component type to look up\n * @returns ComponentGroup, or undefined if type is not registered\n */\n getGroupOf(type: ComponentType): ComponentGroup | undefined {\n const groupId = this._typeToGroupId.get(type);\n if (!groupId) return undefined;\n const group = this._groups.get(groupId);\n if (!group) return undefined;\n return { id: group.id, label: group.label };\n }\n\n /**\n * Get registered component types, optionally filtered by group.\n *\n * @param groupId - If provided, returns only types in that group\n * @returns New array of ComponentType values (safe to mutate).\n * Returns empty array if groupId is unknown.\n */\n getRegisteredTypes(groupId?: string): ComponentType[] {\n if (groupId === undefined) {\n return Array.from(this._factories.keys());\n }\n const group = this._groups.get(groupId);\n if (!group) return [];\n return [...group.types];\n }\n\n /**\n * Unregister a factory for a component type.\n *\n * The type is removed from its group's list and from the reverse lookup.\n * The group record itself is preserved even if it becomes empty.\n *\n * @param type - Component type to remove\n * @returns true if factory was registered and removed, false otherwise\n */\n unregister(type: ComponentType): boolean {\n if (!this._factories.has(type)) return false;\n\n this._factories.delete(type);\n\n const groupId = this._typeToGroupId.get(type);\n if (groupId) {\n const group = this._groups.get(groupId);\n if (group) {\n group.types = group.types.filter((t) => t !== type);\n }\n this._typeToGroupId.delete(type);\n }\n\n return true;\n }\n\n /**\n * Not supported. Use addGroup() to register components within a named group.\n *\n * @throws {Error} Always throws\n */\n register(_type: ComponentType, _factory: IComponentVisualFactory): IFactoryRegistry {\n throw new Error(\n 'GroupedFactoryRegistry does not support register(). Use addGroup() to add components within a named group.'\n );\n }\n}\n","import { ComponentVisualFactoryBase } from '../ComponentVisualFactory';\nimport type { Component } from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport type {VisualContext} from \"../../types\";\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\n createVisual(component: Component, context: VisualContext): 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 // pins (not called if preview - no pins)\n if (component.pins.length > 0){\n this.createPinsVisual(component, context, group);\n }\n\n return group;\n }\n\n private createPinsVisual(component: Component, context: VisualContext, group: THREE.Group){\n\n const cathodeNode = context.getENode(component.pins[0]!);\n if(cathodeNode){\n const cathodeGroup = this.createPinGroup(cathodeNode, 'top');\n cathodeGroup.position.set(0, 0, -1);\n group.add(cathodeGroup);\n }\n\n const anodeNode = context.getENode(component.pins[1]!);\n if(anodeNode){\n const anodeGroup = this.createPinGroup(anodeNode, 'bottom');\n anodeGroup.position.set(0, 0, 1);\n group.add(anodeGroup);\n }\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, VisualContext } 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 createVisual(component: Component, _context: VisualContext): 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, VisualContext } 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, context: VisualContext): 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 // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group, baseMaterial);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n private createPinsVisual(\n component: Component,\n context: VisualContext,\n group: THREE.Group,\n material: THREE.MeshStandardMaterial) {\n const pin1Node = context.getENode(component.pins[0]!);\n if (pin1Node) {\n const pin1Group = this.createPinGroup(pin1Node, 'left');\n pin1Group.position.set(-0.25, 0, 0);\n group.add(pin1Group);\n\n const pin1Counterpart =\n this.createPinCounterpart(pin1Group, material);\n if(!!pin1Counterpart){\n group.add(pin1Counterpart);\n }\n }\n\n const pin2Node = context.getENode(component.pins[1]!);\n if (pin2Node) {\n const pin2Group = this.createPinGroup(pin2Node,'right');\n pin2Group.position.set(0.25, 0, 0);\n group.add(pin2Group);\n\n const pin2Counterpart =\n this.createPinCounterpart(pin2Group, material);\n if(!!pin2Counterpart){\n group.add(pin2Counterpart);\n }\n }\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, VisualContext } 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, context: VisualContext): 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 // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n private createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const inputNode = context.getENode(component.pins[0]!);\n if (inputNode) {\n const pin1Group = this.createPinGroup(inputNode,'left');\n pin1Group.position.set(-0.5, 0, 0);\n group.add(pin1Group);\n }\n\n const outputNode = context.getENode(component.pins[1]!);\n if (outputNode) {\n const outputPinGroup = this.createPinGroup(outputNode,'right');\n outputPinGroup.position.set(0.5, 0, 0);\n group.add(outputPinGroup);\n }\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 pin1 = this.findPinGroup(object3D, 'pin1');\n const outputPin = this.findPinGroup(object3D, 'pin2');\n const hitbox = this.findHitbox(object3D);\n\n if (!ledMesh || !pin1 || !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 pin1.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, VisualContext } from '../../types';\nimport { RingGeometry, LGeometry } from '../../utils/GeometryUtils';\n\n/**\n * Visual factory for Relay components\n *\n * Animation:\n * - Rotates contactor based on open/closed state\n */\nexport class RelayVisualFactory extends ComponentVisualFactoryBase {\n /** Coil ring geometry */\n private readonly COIL_GEOM = RingGeometry(0.35, 0.4, 0.1, 16);\n /** Coil bar geometry */\n private readonly COIL_BAR_GEOM = new THREE.BoxGeometry(0.1, 0.4, 1.4, 2);\n\n private readonly COIL_BAR_Z_OPEN = 0;\n private readonly COIL_BAR_Z_INTERMEDIATE = -0.1;\n private readonly COIL_BAR_Z_CLOSED = -0.2;\n private readonly COIL_BAR_Z_INV_INTERMEDIATE = -0.4;\n private readonly COIL_BAR_Z_INV_OPEN = -0.5;\n\n /** Power In bar geometry */\n private readonly PWIN_BAR_GEOM = new THREE.BoxGeometry(0.1, 0.4, 0.85, 2);\n\n /** normal contactor geom */\n private CONTACTOR_GEOM = LGeometry(0.68, 1.48, 0.1, 140, false, 0.1, 0.4, 16);\n\n /** Rotation for open relay (contactor misaligned) */\n private readonly OPEN_ROTATION =\n new THREE.Euler(-Math.PI / 2,0,-Math.PI);\n /** Rotation for opening/closing relay */\n private readonly INTERMEDIATE_ROTATION =\n new THREE.Euler(-Math.PI / 2,0,-Math.PI - 0.15);\n /** Rotation for closed relay (contactor aligned) */\n private readonly CLOSED_ROTATION =\n new THREE.Euler(-Math.PI / 2,0,-Math.PI - 0.34);\n /** Rotation for opening/closing negative activation logic relay */\n private readonly INVERTED_INTERMEDIATE_ROTATION =\n new THREE.Euler(-Math.PI / 2,0,-Math.PI - 0.54);\n /** Rotation for open negative activation logic relay (contactor misaligned toward the coil) */\n private readonly INVERTED_OPEN_ROTATION =\n new THREE.Euler(-Math.PI / 2,0,-Math.PI - 0.7);\n\n\n createVisual(component: Component, context: VisualContext): 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 const material = new THREE.MeshStandardMaterial({ color: 0xffffff });\n const coilGroup = this.createCoilGroup(component, material);\n group.add(coilGroup);\n coilGroup.position.set(-0.5,0,0);\n\n const contactorGroup = this.createContactorGroup(component, material);\n group.add(contactorGroup);\n contactorGroup.position.set(0,0,-0.7);\n contactorGroup.rotation.copy(this.OPEN_ROTATION)\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group, material);\n }\n\n const powerInBar = new THREE.Mesh(this.PWIN_BAR_GEOM, material);\n group.add(powerInBar);\n powerInBar.rotateY(-Math.PI / 2);\n powerInBar.position.set(0.48,0,-0.7);\n\n // take config into account\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n private createPinsVisual(\n component: Component,\n context: VisualContext,\n group: THREE.Group,\n material: THREE.MeshStandardMaterial) {\n const cmdOutNode = context.getENode(component.pins[1]!);\n if (cmdOutNode) {\n const cmdOutGroup = this.createPinGroup(cmdOutNode, 'left');\n cmdOutGroup.position.set(-0.9, 0, 0.7);\n group.add(cmdOutGroup);\n\n const cmdOutCounterpart =\n this.createPinCounterpart(cmdOutGroup, material);\n if(!!cmdOutCounterpart){\n group.add(cmdOutCounterpart);\n }\n }\n\n const powerInNode = context.getENode(component.pins[2]!);\n if (powerInNode) {\n const powerInGroup = this.createPinGroup(powerInNode, 'right');\n powerInGroup.position.set(0.9, 0, -0.7);\n // to avoid z-fighting\n powerInGroup.renderOrder = 1;\n powerInGroup.children.forEach((child) => {\n child.renderOrder = 1;\n });\n group.add(powerInGroup);\n\n const powerInCounterpart =\n this.createPinCounterpart(powerInGroup, material);\n if(!!powerInCounterpart){\n group.add(powerInCounterpart);\n }\n }\n\n const cmdInNode = context.getENode(component.pins[0]!);\n if (cmdInNode) {\n const cmdInGroup = this.createPinGroup(cmdInNode,'left');\n cmdInGroup.position.set(-0.9, 0, -0.7);\n // addition to group after to avoid z-fighting\n group.add(cmdInGroup);\n\n const cmdInCounterpart =\n this.createPinCounterpart(cmdInGroup, material);\n if(!!cmdInCounterpart){\n group.add(cmdInCounterpart);\n }\n }\n\n const powerOutNode = context.getENode(component.pins[3]!);\n if (powerOutNode) {\n const powerOutGroup = this.createPinGroup(powerOutNode,'right');\n powerOutGroup.position.set(0.9, 0, 0.7);\n group.add(powerOutGroup);\n\n const powerOutCounterpart =\n this.createPinCounterpart(powerOutGroup, material);\n if(!!powerOutCounterpart){\n group.add(powerOutCounterpart);\n }\n }\n }\n\n private createContactorGroup(\n component: Component,\n material: THREE.MeshStandardMaterial): THREE.Group {\n const contactorGroup = new THREE.Group();\n contactorGroup.userData = {\n type: 'component',\n componentId: component.id,\n part: 'contactorGroup',\n initialState: 'open'\n };\n //contactorGroup.add(new THREE.AxesHelper(2));\n contactorGroup.updateMatrix();\n contactorGroup.updateMatrixWorld(true);\n\n\n const contactor = new THREE.Mesh(this.CONTACTOR_GEOM, material);\n contactor.userData = {\n type: 'component',\n componentId: component.id,\n part: 'contactor'};\n contactorGroup.add(contactor);\n contactor.translateZ(-0.2);\n\n contactor.updateMatrix();\n contactor.updateMatrixWorld(true);\n\n return contactorGroup;\n }\n\n private createCoilGroup(\n component: Component,\n material: THREE.MeshStandardMaterial): THREE.Group {\n\n const coilGroup = new THREE.Group();\n coilGroup.userData = {\n type: 'component',\n componentId: component.id,\n part: 'coilGroup'\n };\n\n const partsUserData = {\n type: 'component',\n componentId: component.id,\n part: 'coil'\n }\n\n const addCoil = (z:number, xr:number) =>{\n const coil = new THREE.Mesh(this.COIL_GEOM, material);\n coil.userData = {...partsUserData};\n coil.position.set(0,0, z);\n coil.rotateX(xr);\n coilGroup.add(coil);\n }\n addCoil(0.6, -0.03);\n addCoil(0.4, 0.03);\n addCoil(0.2, -0.03);\n addCoil(0, 0.03);\n addCoil(-0.2, -0.03);\n addCoil(-0.4, 0.03);\n addCoil(-0.6, -0.03);\n\n const bar = new THREE.Mesh(this.COIL_BAR_GEOM, material);\n bar.userData = {...partsUserData, part: 'coilBar'};\n coilGroup.add(bar);\n\n return coilGroup;\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 coilBar = this.findCoilBar(object3D);\n\n const negLog = contactorGroup?\n contactorGroup.userData.initialState === 'closed': false;\n\n if (!state) {\n // Edition mode - set to initial state\n if (contactorGroup) {\n contactorGroup.rotation.copy(negLog?\n this.CLOSED_ROTATION:this.OPEN_ROTATION);\n }\n if (coilBar) {\n\n let gf = negLog?\n this.COIL_BAR_Z_CLOSED:this.COIL_BAR_Z_OPEN;\n coilBar.position.set(0,0,gf);\n }\n return;\n }\n\n const relayState = state as RelayState;\n if (contactorGroup) {\n if (relayState.isInTransition) {\n const targetRotation =\n negLog ? this.INVERTED_INTERMEDIATE_ROTATION\n : this.INTERMEDIATE_ROTATION;\n contactorGroup.rotation.copy(targetRotation);\n } else if (relayState.isClosed) {\n // Closed position - contactor aligned\n contactorGroup.rotation.copy(this.CLOSED_ROTATION);\n } else {\n // Open position - contactor misaligned\n const targetRotation =\n negLog ? this.INVERTED_OPEN_ROTATION\n : this.OPEN_ROTATION;\n contactorGroup.rotation.copy(targetRotation);\n }\n }\n\n if (coilBar) {\n if (relayState.isInTransition) {\n coilBar.position.set(0,0, negLog?\n this.COIL_BAR_Z_INV_INTERMEDIATE: this.COIL_BAR_Z_INTERMEDIATE);\n } else if (relayState.isClosed) {\n coilBar.position.set(0,0, this.COIL_BAR_Z_CLOSED);\n } else {\n coilBar.position.set(0,0, negLog?\n this.COIL_BAR_Z_INV_OPEN: this.COIL_BAR_Z_OPEN);\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.Object3D && child.userData.part === 'contactorGroup') {\n contactorGroup = child;\n }\n });\n\n return contactorGroup;\n }\n\n /**\n * Find the coil bar 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 findCoilBar(object3D: THREE.Object3D): THREE.Mesh | null {\n let coilBar: THREE.Mesh | null = null;\n\n object3D.traverse((child) => {\n if (child.userData.part === 'coilBar') {\n // @ts-ignore\n coilBar = child;\n }\n });\n return coilBar;\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, VisualContext } 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 /** LED lit emissive intensity */\n private static readonly LED_LIT_INTENSITY = 1.0;\n\n createVisual(component: Component, context: VisualContext): 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 material = 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, material);\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 // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group, material);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n private createPinsVisual(\n component: Component,\n context: VisualContext,\n group: THREE.Group,\n material: THREE.MeshStandardMaterial) {\n const inputNode = context.getENode(component.pins[0]!);\n if (inputNode) {\n const pin1Group = this.createPinGroup(inputNode,'left');\n pin1Group.position.set(-0.25, 0, 0);\n group.add(pin1Group);\n\n const pin1Counterpart =\n this.createPinCounterpart(pin1Group, material);\n if(!!pin1Counterpart){\n group.add(pin1Counterpart);\n }\n }\n\n const outputNode = context.getENode(component.pins[1]!);\n if (outputNode) {\n const pin2Group = this.createPinGroup(outputNode,'right');\n pin2Group.position.set(0.25, 0, 0);\n group.add(pin2Group);\n\n const pin2Counterpart =\n this.createPinCounterpart(pin2Group, material);\n if(!!pin2Counterpart){\n group.add(pin2Counterpart);\n }\n }\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, VisualContext } 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 readonly CLOSED_ROTATION = new THREE.Euler(0, 0, 0);\n /** Rotation for opening/closing switch */\n private readonly INTERMEDIATE_ROTATION = new THREE.Euler(0, 0.3, 0);\n /** Rotation for open switch (contactor misaligned) */\n private readonly OPEN_ROTATION = new THREE.Euler(0, 0.6, 0);\n\n createVisual(component: Component, context: VisualContext): 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.6, 3, 1);\n group.add(hitbox);\n hitbox.position.set(-0.2,0,0.3);\n\n const material = new THREE.MeshStandardMaterial({ color: 0xffffff });\n // Contactor\n const contactorGroup = new THREE.Group();\n contactorGroup.userData = {\n type: 'component',\n componentId: component.id,\n part: 'contactor',\n initialState: 'open',\n };\n contactorGroup.position.set(0.6, 0, 0);\n contactorGroup.rotation.copy(this.OPEN_ROTATION);\n group.add(contactorGroup);\n\n const contactorGeometry = new THREE.BoxGeometry(1.4, 0.6, 0.1);\n const contactor = new THREE.Mesh(contactorGeometry, material);\n contactor.position.set(-0.7, 0, 0);\n\n contactorGroup.add(contactor);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group, material);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n private createPinsVisual(\n component: Component,\n context: VisualContext,\n group: THREE.Group,\n material: THREE.MeshStandardMaterial) {\n const inputNode = context.getENode(component.pins[0]!);\n if (inputNode) {\n const inputPinGroup = this.createPinGroup(inputNode,'left');\n inputPinGroup.position.set(-1, 0, 0);\n group.add(inputPinGroup);\n\n const inputPinCounterpart =\n this.createPinCounterpart(inputPinGroup, material);\n if(!!inputPinCounterpart){\n group.add(inputPinCounterpart);\n }\n }\n\n const outputNode = context.getENode(component.pins[1]!);\n if (outputNode) {\n const outputPinGroup = this.createPinGroup(outputNode, 'right');\n outputPinGroup.position.set(0.6, 0, 0);\n group.add(outputPinGroup);\n\n const outputPinCounterpart =\n this.createPinCounterpart(outputPinGroup, material);\n if(!!outputPinCounterpart){\n group.add(outputPinCounterpart);\n }\n }\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(this.CLOSED_ROTATION);\n } else {\n contactorGroup.rotation.copy(this.OPEN_ROTATION);\n }\n return;\n }\n\n const switchState = state as SwitchState;\n if (switchState.isInTransition) {\n contactorGroup.rotation.copy(this.INTERMEDIATE_ROTATION);\n } else if (switchState.isClosed) {\n // Closed position - contactor aligned\n contactorGroup.rotation.copy(this.CLOSED_ROTATION);\n } else {\n // Open position - contactor misaligned\n contactorGroup.rotation.copy(this.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.Group && 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 {\n type Component,\n type ComponentState,\n type DoubleThrowSwitchState,\n} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport type { ConfigFormDefinition, VisualContext } from '../../types';\n\n/**\n * Visual factory for Double Switch components\n *\n * Creates:\n * - 2 * 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 DoubleThrowSwitchVisualFactory extends ComponentVisualFactoryBase {\n /** Rotation for switch to input 1 */\n private readonly INPUT1_ROTATION = new THREE.Euler(0, 0.32, 0);\n /** Rotation for switch toggling */\n private readonly INTERMEDIATE_ROTATION = new THREE.Euler(0,0,0);\n /** Rotation for switch to input 2 */\n private readonly INPUT2_ROTATION = new THREE.Euler(0, -0.32, 0);\n\n createVisual(component: Component, context: VisualContext): 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.6, 3, 1.6);\n group.add(hitbox);\n hitbox.position.set(-0.2,0,0);\n\n const material = new THREE.MeshStandardMaterial({ color: 0xffffff });\n // Contactor\n const contactorGroup = new THREE.Group();\n contactorGroup.userData = {\n type: 'component',\n componentId: component.id,\n part: 'contactor',\n initialState: 'input1',\n };\n contactorGroup.position.set(0.6, 0, 0);\n contactorGroup.rotation.copy(this.INPUT1_ROTATION);\n group.add(contactorGroup);\n\n const contactorGeometry = new THREE.BoxGeometry(1.4, 0.6, 0.1);\n const contactor = new THREE.Mesh(contactorGeometry, material);\n contactor.position.set(-0.7, 0, 0);\n\n contactorGroup.add(contactor);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group, material);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n private createPinsVisual(\n component: Component,\n context: VisualContext,\n group: THREE.Group,\n material: THREE.MeshStandardMaterial) {\n\n const input1Node = context.getENode(component.pins[0]!);\n if (input1Node) {\n const input1PinGroup =\n this.createPinGroup(input1Node, 'left', new THREE.Euler(0.4, 0, 0));\n input1PinGroup.position.set(-1, 0, 0.5);\n group.add(input1PinGroup);\n\n const input1PinCounterpart =\n this.createPinCounterpart(input1PinGroup, material);\n if(!!input1PinCounterpart){\n group.add(input1PinCounterpart);\n }\n }\n\n const input2Node = context.getENode(component.pins[1]!);\n if (input2Node) {\n const input2PinGroup =\n this.createPinGroup(input2Node,'left', new THREE.Euler(-0.4, 0, 0));\n input2PinGroup.position.set(-1, 0, -0.5);\n group.add(input2PinGroup);\n\n const input2PinCounterpart =\n this.createPinCounterpart(input2PinGroup, material);\n if(!!input2PinCounterpart){\n group.add(input2PinCounterpart);\n }\n }\n\n const input3Node = context.getENode(component.pins[2]!);\n if (input3Node) {\n const input3PinGroup =\n this.createPinGroup(input3Node,'right');\n input3PinGroup.position.set(0.6, 0, 0);\n group.add(input3PinGroup);\n\n const input3PinCounterpart =\n this.createPinCounterpart(input3PinGroup, material);\n if(!!input3PinCounterpart){\n group.add(input3PinCounterpart);\n }\n }\n }\n\n /**\n * Get config form definition for Double Switch\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: 'input1 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 \"input1\"/\"input2\" 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 === 'input1');\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 \"input1\"/\"input2\" 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 ? 'input1' : 'input2');\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') === 'input2') {\n contactorGroup.userData.initialState = 'input2';\n } else {\n contactorGroup.userData.initialState = 'input1';\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 input1/2 state\n */\n override updateAnimation(object3D: THREE.Object3D, state: ComponentState | null): void {\n const contactorGroup = this.findContactorGroup(object3D);\n\n if (!contactorGroup) return;\n if (!state) {\n if (contactorGroup.userData.initialState === 'input1') {\n contactorGroup.rotation.copy(this.INPUT1_ROTATION);\n } else {\n contactorGroup.rotation.copy(this.INPUT2_ROTATION);\n }\n return;\n }\n\n const switchState = state as DoubleThrowSwitchState;\n if (switchState.isInTransition) {\n contactorGroup.rotation.copy(this.INTERMEDIATE_ROTATION);\n } else if (switchState.state === 'input1') {\n contactorGroup.rotation.copy(this.INPUT1_ROTATION);\n } else {\n contactorGroup.rotation.copy(this.INPUT2_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.Group && child.userData.part === 'contactor') {\n contactorGroup = child;\n }\n });\n\n return contactorGroup;\n }\n}\n","import { ComponentVisualFactoryBase } from '../ComponentVisualFactory';\nimport {type Component, type ComponentState, InverterState} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { CyclicTrapezoidGeometry } from '../../utils/GeometryUtils';\nimport type {ConfigFormDefinition, VisualContext} from '../../types';\n\n/**\n * Visual factory for Inverter/Buffer components\n *\n * Creates:\n * - Inverter triangle or Buffer trapezoid extrude geom mesh\n * - Vcc, input and output pin group\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when component is high (based on simulation state)\n */\nexport class InverterVisualFactory extends ComponentVisualFactoryBase {\n /** Inverter high color (white glow) */\n private static readonly HIGH_COLOR = 0xffffff;\n /** Inverter high emissive intensity */\n private static readonly HIGH_INTENSITY = 0.3;\n\n /** Shared low Inverter envelope geometry */\n private readonly inverterLowGeometry = CyclicTrapezoidGeometry(0.8, 1.6, 0, 0.08, 0.4, 16);\n /** Shared transient Inverter envelope geometry */\n private readonly inverterTransientGeometry = CyclicTrapezoidGeometry(0.8, 1.6, 0, 0.17, 0.4, 16);\n /** Shared high Inverter envelope geometry */\n private readonly inverterHighGeometry = CyclicTrapezoidGeometry(0.8, 1.6, 0, 0.4, 0.4, 16);\n\n /** Shared low Buffer envelope geometry */\n private readonly bufferLowGeometry = CyclicTrapezoidGeometry(1, 1.6, 0.61, 0.08, 0.4, 16);\n /** Shared transient Buffer envelope geometry */\n private readonly bufferTransientGeometry = CyclicTrapezoidGeometry(1, 1.6, 0.61, 0.23, 0.4, 16);\n /** Shared high Buffer envelope geometry */\n private readonly bufferHighGeometry = CyclicTrapezoidGeometry(1, 1.6, 0.61, 0.5, 0.4, 16);\n\n\n createVisual(component: Component, context: VisualContext): THREE.Object3D {\n\n const material = new THREE.MeshStandardMaterial({ color: 0xffffff });\n material.emissive.setHex(InverterVisualFactory.HIGH_COLOR);\n material.emissiveIntensity = 0;\n\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 material: material,\n variant: 'inverter'\n };\n\n // Component hitbox (invisible, raycastable)\n const hitbox = this.createComponentHitbox(component.id, group.id, 1.6, 2, 1.6);\n group.add(hitbox);\n // create an inverter by default\n this.replaceEnvelope(group, false);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0){\n this.createPinsVisual(component, context, group, group.userData.material);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n private createPinsVisual(\n component: Component,\n context: VisualContext,\n group: THREE.Group,\n material: THREE.MeshStandardMaterial){\n\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode){\n const vccGroup = this.createPinGroup(vccNode, 'top', new THREE.Euler(0, 0, -0.8));\n vccGroup.position.set(-0.27, 0, -0.56);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[3]!);\n if (gndNode){\n const gndGroup = this.createPinGroup(gndNode, 'bottom', new THREE.Euler(0, 0, -0.8));\n gndGroup.position.set(-0.27, 0, 0.56);\n group.add(gndGroup);\n }\n\n const inputNode = context.getENode(component.pins[1]!);\n if (inputNode){\n const inputGroup = this.createPinGroup(inputNode, 'left');\n inputGroup.position.set(-0.5, 0, 0);\n group.add(inputGroup);\n }\n\n const outputNode = context.getENode(component.pins[2]!);\n if(outputNode){\n const outputGroup = this.createPinGroup(outputNode, 'right');\n outputGroup.position.set(0.45, 0, 0);\n group.add(outputGroup);\n\n // this counterpart act as negativeMarker when component is in its inverter config\n const outputPinCounterpart =\n this.createPinCounterpart(outputGroup, material);\n if(!!outputPinCounterpart){\n outputPinCounterpart.userData.part = 'negativeMarker';\n group.add(outputPinCounterpart);\n }\n }\n }\n\n private replaceEnvelope(group: THREE.Object3D, activationLogic: boolean): THREE.Mesh {\n let material: THREE.MeshStandardMaterial | null = null;\n const oldEnvelope = this.findEnvelopeMesh(group);\n if (oldEnvelope) {\n // case where envelope of the good type (buffer or inverter) already exists\n if (activationLogic === oldEnvelope.userData.activationLogic) {\n return oldEnvelope;\n }\n // else we remove the old envelope before recreating it\n material = oldEnvelope.material;\n group.remove(oldEnvelope);\n }\n\n if(!material){\n material = group.userData.material!!;\n }\n\n const envelope = activationLogic\n ? new THREE.Mesh(this.bufferLowGeometry, material!!)\n : new THREE.Mesh(this.inverterHighGeometry, material!!);\n envelope.userData = {\n type: 'component',\n componentId: group.userData.componentId,\n part: 'envelope',\n activationLogic: activationLogic,\n initialState: activationLogic ? 'low' : 'high',\n };\n envelope.rotateX(-Math.PI / 2);\n const envX = activationLogic ? -0.05 : -0.1;\n envelope.position.set(envX, -0.05, 0);\n group.add(envelope);\n return envelope;\n }\n\n /**\n * Get config form definition for Inverter\n *\n * @param config - Optional current config to determine disabled state of transitionSpan\n * @returns Form definition with defaultLogicFamily dropdown, activationLogic boolean, and transitionSpan number\n */\n override getConfigFormDefinition(config?: Map<string, string>): ConfigFormDefinition | null {\n const logicFamily = config?.get('defaultLogicFamily') ?? 'CMOS1';\n return {\n fields: [\n {\n key: 'defaultLogicFamily',\n label: 'Logic Family',\n type: 'dropdown',\n options: { CMOS: 'CMOS1', TTL: 'TTL1', Sandbox: 'Sandbox' },\n },\n {\n key: 'activationLogic',\n label: 'Activation Logic',\n type: 'boolean',\n },\n {\n key: 'transitionSpan',\n label: 'Propagation delay (ticks)',\n type: 'number',\n min: 1,\n disabled: logicFamily !== 'Sandbox',\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\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 formData.set('defaultLogicFamily', config.get('defaultLogicFamily') ?? 'CMOS1');\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\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 config.set('defaultLogicFamily', formData.get('defaultLogicFamily') ?? 'CMOS1');\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 envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n const negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n const vccVisual = this.findPinVisual(object3D, 'vcc');\n const gndVisual = this.findPinVisual(object3D, 'gnd');\n\n const inverterVariant = (config && config.has('activationLogic'))? config.get('activationLogic') !== 'positive': true;\n\n if (inverterVariant) {\n this.replaceEnvelope(object3D, false);\n if (object3D.userData.variant !== 'inverter') {\n object3D.userData.variant = 'inverter';\n // @ts-ignore\n negativeMarkerMesh?.geometry.scale(10,10,10);\n\n if (!!vccVisual) {\n vccVisual.setRotationFromEuler(new THREE.Euler(0, 0, -0.8));\n vccVisual.parent!.position.set(-0.27, 0, -0.55);\n }\n if (!!gndVisual) {\n gndVisual.setRotationFromEuler(new THREE.Euler(0, 0, -0.8));\n gndVisual.parent!.position.set(-0.27, 0, 0.56);\n }\n }\n } else {\n if(object3D.userData.variant !== 'buffer'){\n object3D.userData.variant = 'buffer';\n this.replaceEnvelope(object3D, true);\n // @ts-ignore\n negativeMarkerMesh?.geometry.scale(0.1,0.1,0.1);\n\n if (!!vccVisual) {\n vccVisual.setRotationFromEuler(new THREE.Euler(0, 0, -0.5));\n vccVisual.parent!.position.set(-0.27, 0, -0.65);\n }\n if (!!gndVisual) {\n gndVisual.setRotationFromEuler(new THREE.Euler(0, 0, -0.5));\n gndVisual.parent!.position.set(-0.27, 0, 0.65);\n }\n }\n }\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update Inverter animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The Inverter'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\n const isBuffer = envelopeMesh.userData.activationLogic === true;\n const lowGeometry = isBuffer ? this.bufferLowGeometry : this.inverterLowGeometry;\n const transientGeometry = isBuffer\n ? this.bufferTransientGeometry\n : this.inverterTransientGeometry;\n const highGeometry = isBuffer ? this.bufferHighGeometry : this.inverterHighGeometry;\n\n if (!state) {\n if (envelopeMesh.userData.initialState === 'high') {\n envelopeMesh.geometry = highGeometry;\n envelopeMesh.material.emissiveIntensity = InverterVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = lowGeometry;\n envelopeMesh.material.emissiveIntensity = 0;\n }\n return;\n }\n\n const bufferState = state as InverterState;\n if (bufferState.isHigh) {\n envelopeMesh.geometry = highGeometry;\n envelopeMesh.material.emissiveIntensity = InverterVisualFactory.HIGH_INTENSITY;\n } else if (bufferState.isInTransition) {\n envelopeMesh.geometry = transientGeometry;\n envelopeMesh.material.emissiveIntensity = 0.5 * InverterVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = lowGeometry;\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 /**\n * Find the negative marker mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The negative marker mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'negativeMarker'\n */\n protected findNegativeMarkerMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let negativeMarkerMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'negativeMarker') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n negativeMarkerMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n return negativeMarkerMesh;\n }\n}\n","import { ComponentVisualFactoryBase } from '../ComponentVisualFactory';\nimport {type Component, type ComponentState, type NandGateState} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { AndGateGeometry } from '../../utils/GeometryUtils';\nimport type {ConfigFormDefinition, VisualContext} from '../../types';\n\n/**\n * Visual factory for NAND gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class NandGateVisualFactory extends ComponentVisualFactoryBase {\n /** Gate high color */\n protected static readonly HIGH_COLOR = 0xffffff;\n /** Gate high emissive intensity */\n protected static readonly HIGH_INTENSITY = 0.3;\n /** Shared open envelope geometry */\n protected readonly lowGeometry = AndGateGeometry(1.5, 1.6, 0.1, 0.4, 16);\n /** Shared transient envelope geometry */\n protected readonly transientGeometry = AndGateGeometry(1.5, 1.6, 0.45, 0.4, 16);\n /** Shared transient envelope geometry */\n protected readonly highGeometry = AndGateGeometry(1.5, 1.6, 0.799, 0.4, 16);\n /** Shared material for negative marker **/\n protected static readonly negativeMarkerMaterial = new THREE.MeshStandardMaterial({\n color: 0xfafafa,\n });\n /** Shared geometry for negative marker **/\n protected static readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.2,\n 0.2,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override defaultRotation() {\n return Math.PI;\n }\n\n createVisual(component: Component, context: VisualContext): 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, 1.8);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(NandGateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(0, 0.35, 0);\n group.add(envelope);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0){\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected createPinsVisual(component: Component, context: VisualContext, group: THREE.Group){\n\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom');\n vccGroup.position.set(0.15, 0, 0.79);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[4]!);\n if (gndNode){\n const gndGroup = this.createPinGroup(gndNode, 'top');\n gndGroup.position.set(0.15, 0, -0.79);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right');\n input1Group.position.set(0.75, 0, 0.5);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right');\n input2Group.position.set(0.75, 0, -0.5);\n group.add(input2Group);\n }\n\n const outputNode = context.getENode(component.pins[3]!);\n if(outputNode){\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-0.7, 0, 0);\n group.add(outputGroup);\n }\n }\n\n\n /**\n * Get config form definition\n *\n * @param config - Optional current config to determine disabled state of transitionSpan\n * @returns Form definition with defaultLogicFamily dropdown, activationLogic boolean, and transitionSpan number\n */\n override getConfigFormDefinition(config?: Map<string, string>): ConfigFormDefinition | null {\n const logicFamily = config?.get('defaultLogicFamily') ?? 'CMOS1';\n return {\n fields: [\n {\n key: 'defaultLogicFamily',\n label: 'Logic Family',\n type: 'dropdown',\n options: { CMOS: 'CMOS1', TTL: 'TTL1', Sandbox: 'Sandbox' },\n },\n {\n key: 'activationLogic',\n label: 'Activation Logic',\n type: 'boolean',\n },\n {\n key: 'transitionSpan',\n label: 'Propagation delay (ticks)',\n type: 'number',\n min: 1,\n disabled: logicFamily !== 'Sandbox',\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\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 formData.set('defaultLogicFamily', config.get('defaultLogicFamily') ?? 'CMOS1');\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\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 config.set('defaultLogicFamily', formData.get('defaultLogicFamily') ?? 'CMOS1');\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 envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n NandGateVisualFactory.negativeMarkerGeometry,\n NandGateVisualFactory.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-0.7, 0.15, -0.65);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The component 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 === 'high') {\n envelopeMesh.geometry = this.highGeometry;\n envelopeMesh.material.emissiveIntensity = NandGateVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = this.lowGeometry;\n envelopeMesh.material.emissiveIntensity = 0;\n }\n return;\n }\n\n const gateState = state as NandGateState;\n if (gateState.isHigh) {\n envelopeMesh.geometry = this.highGeometry;\n envelopeMesh.material.emissiveIntensity = NandGateVisualFactory.HIGH_INTENSITY;\n } else if (gateState.isInTransition) {\n envelopeMesh.geometry = this.transientGeometry;\n envelopeMesh.material.emissiveIntensity = 0.5 * NandGateVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = this.lowGeometry;\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 protected 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 /**\n * Find the negative marker mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The negative marker mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'negativeMarker'\n */\n protected findNegativeMarkerMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let negativeMarkerMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'negativeMarker') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n negativeMarkerMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n return negativeMarkerMesh;\n }\n}\n","import {type Component} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { AndGateGeometry } from '../../utils/GeometryUtils';\nimport { NandGateVisualFactory } from './NandGateVisualFactory';\nimport type { VisualContext } from '../../types';\n\n/**\n * Visual factory for NAND gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class Nand4GateVisualFactory extends NandGateVisualFactory {\n /** Shared open envelope geometry */\n protected override readonly lowGeometry = AndGateGeometry(2, 3.6, 0.13, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly transientGeometry = AndGateGeometry(2, 3.6, 0.55, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly highGeometry = AndGateGeometry(2, 3.6, 1, 0.4, 16);\n /** Shared geometry for negative marker **/\n protected static override readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.25,\n 0.25,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override createVisual(component: Component, context: VisualContext): 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.5, 2, 3.8);\n //hitbox.rotateY(Math.PI / 2);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(Nand4GateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(-0.25, 0.35, 0);\n group.add(envelope);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected override createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom', new THREE.Euler(0, 0, 0.23));\n vccGroup.position.set(0.15, 0, 1.73);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[6]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top', new THREE.Euler(0, 0, 0.23));\n gndGroup.position.set(0.15, 0, -1.73);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right');\n input1Group.position.set(0.75, 0, 1.5);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right');\n input2Group.position.set(0.75, 0, 0.5);\n group.add(input2Group);\n }\n\n const input3Node = context.getENode(component.pins[3]!);\n if (input3Node) {\n const input3Group = this.createPinGroup(input3Node, 'right');\n input3Group.position.set(0.75, 0, -0.5);\n group.add(input3Group);\n }\n\n const input4Node = context.getENode(component.pins[4]!);\n if (input4Node) {\n const input4Group = this.createPinGroup(input4Node, 'right');\n input4Group.position.set(0.75, 0, -1.5);\n group.add(input4Group);\n }\n\n const outputNode = context.getENode(component.pins[5]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode,'left');\n outputGroup.position.set(-1.22, 0, 0);\n group.add(outputGroup);\n }\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n Nand4GateVisualFactory.negativeMarkerGeometry,\n Nand4GateVisualFactory.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-1, 0.15, -1.3);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n}\n","import {type Component} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { AndGateGeometry } from '../../utils/GeometryUtils';\nimport { NandGateVisualFactory } from './NandGateVisualFactory';\nimport type { VisualContext } from '../../types';\n\n/**\n * Visual factory for NAND gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class Nand8GateVisualFactory extends NandGateVisualFactory {\n /** Shared open envelope geometry */\n protected override readonly lowGeometry = AndGateGeometry(2.6, 7.5, 0.16, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly transientGeometry = AndGateGeometry(2.6, 7.5, 0.76, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly highGeometry = AndGateGeometry(2.6, 7.5, 1.3, 0.4, 16);\n /** Shared geometry for negative marker **/\n protected static override readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.35,\n 0.35,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override createVisual(component: Component, context: VisualContext): 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, 3, 2, 7.6);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(Nand8GateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(-0.1, 0.35, 0);\n group.add(envelope);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected override createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom', new THREE.Euler(0, 0, 0.5));\n vccGroup.position.set(0.7, 0, 3.5);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[10]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top', new THREE.Euler(0, 0, 0.5));\n gndGroup.position.set(0.7, 0, -3.5);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right');\n input1Group.position.set(1.2, 0, 3.45);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right');\n input2Group.position.set(1.2, 0, 2.5);\n group.add(input2Group);\n }\n\n const input3Node = context.getENode(component.pins[3]!);\n if (input3Node) {\n const input3Group = this.createPinGroup(input3Node, 'right');\n input3Group.position.set(1.2, 0, 1.5);\n group.add(input3Group);\n }\n\n const input4Node = context.getENode(component.pins[4]!);\n if (input4Node) {\n const input4Group = this.createPinGroup(input4Node, 'right');\n input4Group.position.set(1.2, 0, 0.5);\n group.add(input4Group);\n }\n\n const input5Node = context.getENode(component.pins[5]!);\n if (input5Node) {\n const input5Group = this.createPinGroup(input5Node, 'right');\n input5Group.position.set(1.2, 0, -0.5);\n group.add(input5Group);\n }\n\n const input6Node = context.getENode(component.pins[6]!);\n if (input6Node) {\n const input6Group = this.createPinGroup(input6Node, 'right');\n input6Group.position.set(1.2, 0, -1.5);\n group.add(input6Group);\n }\n\n const input7Node = context.getENode(component.pins[7]!);\n if (input7Node) {\n const input7Group = this.createPinGroup(input7Node, 'right');\n input7Group.position.set(1.2, 0, -2.5);\n group.add(input7Group);\n }\n\n const input8Node = context.getENode(component.pins[8]!);\n if (input8Node) {\n const input8Group = this.createPinGroup(input8Node, 'right');\n input8Group.position.set(1.2, 0, -3.45);\n group.add(input8Group);\n }\n\n const outputNode = context.getENode(component.pins[9]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-1.39, 0, -0.05);\n group.add(outputGroup);\n }\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n Nand8GateVisualFactory.negativeMarkerGeometry,\n Nand8GateVisualFactory.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-0.8, 0.15, -2.7);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n}\n","import { ComponentVisualFactoryBase } from '../ComponentVisualFactory';\nimport {type Component, type ComponentState, type NorGateState} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { OrGateGeometry } from '../../utils/GeometryUtils';\nimport type { ConfigFormDefinition, VisualContext } from '../../types';\n\n/**\n * Visual factory for NOR gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class NorGateVisualFactory extends ComponentVisualFactoryBase {\n /** Gate high color */\n protected static readonly HIGH_COLOR = 0xffffff;\n /** Gate high emissive intensity */\n protected static readonly HIGH_INTENSITY = 0.3;\n /** Shared open envelope geometry */\n protected readonly lowGeometry = OrGateGeometry(1.5, 1.6, 0.1, 0.4, 16);\n /** Shared transient envelope geometry */\n protected readonly transientGeometry = OrGateGeometry(1.5, 1.6, 0.4, 0.4, 16);\n /** Shared transient envelope geometry */\n protected readonly highGeometry = OrGateGeometry(1.5, 1.6, 0.799, 0.4, 16);\n /** Shared material for negative marker **/\n protected static readonly negativeMarkerMaterial = new THREE.MeshStandardMaterial({\n color: 0xfafafa,\n });\n /** Shared geometry for negative marker **/\n protected static readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.2,\n 0.2,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override defaultRotation() {\n return Math.PI;\n }\n\n createVisual(component: Component, context: VisualContext): 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, 1.8);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(NorGateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(0, 0.35, 0);\n group.add(envelope);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom');\n vccGroup.position.set(0.15, 0, 0.79);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[4]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top');\n gndGroup.position.set(0.15, 0, -0.79);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right', new THREE.Euler(0.45, 0, 0));\n input1Group.position.set(0.54, 0, 0.5);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right', new THREE.Euler(-0.45, 0, 0));\n input2Group.position.set(0.54, 0, -0.5);\n group.add(input2Group);\n }\n\n const outputNode = context.getENode(component.pins[3]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-0.7, 0, 0);\n group.add(outputGroup);\n }\n }\n\n /**\n * Get config form definition\n *\n * @param config - Optional current config to determine disabled state of transitionSpan\n * @returns Form definition with defaultLogicFamily dropdown, activationLogic boolean, and transitionSpan number\n */\n override getConfigFormDefinition(config?: Map<string, string>): ConfigFormDefinition | null {\n const logicFamily = config?.get('defaultLogicFamily') ?? 'CMOS1';\n return {\n fields: [\n {\n key: 'defaultLogicFamily',\n label: 'Logic Family',\n type: 'dropdown',\n options: { CMOS: 'CMOS1', TTL: 'TTL1', Sandbox: 'Sandbox' },\n },\n {\n key: 'activationLogic',\n label: 'Activation Logic',\n type: 'boolean',\n },\n {\n key: 'transitionSpan',\n label: 'Propagation delay (ticks)',\n type: 'number',\n min: 1,\n disabled: logicFamily !== 'Sandbox',\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\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 formData.set('defaultLogicFamily', config.get('defaultLogicFamily') ?? 'CMOS1');\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\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 config.set('defaultLogicFamily', formData.get('defaultLogicFamily') ?? 'CMOS1');\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 envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n NorGateVisualFactory.negativeMarkerGeometry,\n NorGateVisualFactory.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-0.7, 0.15, -0.65);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The component 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 === 'high') {\n envelopeMesh.geometry = this.highGeometry;\n envelopeMesh.material.emissiveIntensity = NorGateVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = this.lowGeometry;\n envelopeMesh.material.emissiveIntensity = 0;\n }\n return;\n }\n\n const gateState = state as NorGateState;\n if (gateState.isHigh) {\n envelopeMesh.geometry = this.highGeometry;\n envelopeMesh.material.emissiveIntensity = NorGateVisualFactory.HIGH_INTENSITY;\n } else if (gateState.isInTransition) {\n envelopeMesh.geometry = this.transientGeometry;\n envelopeMesh.material.emissiveIntensity = 0.5 * NorGateVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = this.lowGeometry;\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 protected 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 /**\n * Find the negative marker mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The negative marker mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'negativeMarker'\n */\n protected findNegativeMarkerMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let negativeMarkerMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'negativeMarker') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n negativeMarkerMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n return negativeMarkerMesh;\n }\n}\n","import {type Component} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { OrGateGeometry } from '../../utils/GeometryUtils';\nimport { NorGateVisualFactory } from './NorGateVisualFactory';\nimport type { VisualContext } from '../../types';\n\n/**\n * Visual factory for NOR gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class Nor4GateVisualFactory extends NorGateVisualFactory {\n /** Shared open envelope geometry */\n protected override readonly lowGeometry = OrGateGeometry(2, 3.6, 0.13, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly transientGeometry = OrGateGeometry(2, 3.6, 0.23, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly highGeometry = OrGateGeometry(2, 3.6, 1, 0.4, 16);\n /** Shared geometry for negative marker **/\n protected static override readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.25,\n 0.25,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override createVisual(component: Component, context: VisualContext): 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.5, 2, 3.8);\n //hitbox.rotateY(Math.PI / 2);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(Nor4GateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(-0.25, 0.35, 0);\n group.add(envelope);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected override createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom', new THREE.Euler(0, 0, 0.23));\n vccGroup.position.set(0.15, 0, 1.73);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[6]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top', new THREE.Euler(0, 0, 0.23));\n gndGroup.position.set(0.15, 0, -1.73);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right', new THREE.Euler(0.6, 0, 0));\n input1Group.position.set(0.51, 0, 1.5);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right', new THREE.Euler(0.1, 0, 0));\n input2Group.position.set(0.07, 0, 0.5);\n group.add(input2Group);\n }\n\n const input3Node = context.getENode(component.pins[3]!);\n if (input3Node) {\n const input3Group = this.createPinGroup(input3Node, 'right', new THREE.Euler(-0.1, 0, 0));\n input3Group.position.set(0.07, 0, -0.5);\n group.add(input3Group);\n }\n\n const input4Node = context.getENode(component.pins[4]!);\n if (input4Node) {\n const input4Group = this.createPinGroup(input4Node, 'right', new THREE.Euler(-0.6, 0, 0));\n input4Group.position.set(0.51, 0, -1.5);\n group.add(input4Group);\n }\n\n const outputNode = context.getENode(component.pins[5]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-1.22, 0, 0);\n group.add(outputGroup);\n }\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n Nor4GateVisualFactory.negativeMarkerGeometry,\n Nor4GateVisualFactory.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-1, 0.15, -1.3);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n}\n","import {type Component} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { OrGateGeometry } from '../../utils/GeometryUtils';\nimport { NorGateVisualFactory } from './NorGateVisualFactory';\nimport type { VisualContext } from '../../types';\n\n/**\n * Visual factory for NOR gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class Nor8GateVisualFactory extends NorGateVisualFactory {\n /** Shared open envelope geometry */\n protected override readonly lowGeometry = OrGateGeometry(2.6, 7.5, 0.16, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly transientGeometry = OrGateGeometry(2.6, 7.5, 0.35, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly highGeometry = OrGateGeometry(2.6, 7.5, 1.3, 0.4, 16);\n /** Shared geometry for negative marker **/\n protected static override readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.35,\n 0.35,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override createVisual(component: Component, context: VisualContext): 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, 3, 2, 7.6);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(Nor8GateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(-0.1, 0.35, 0);\n group.add(envelope);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected override createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom', new THREE.Euler(0, 0, 0.5));\n vccGroup.position.set(0.7, 0, 3.5);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[10]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top',new THREE.Euler(0, 0, 0.5));\n gndGroup.position.set(0.7, 0, -3.5);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right', new THREE.Euler(0.7, 0, 0));\n input1Group.position.set(0.9, 0, 3.45);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right', new THREE.Euler(0.53, 0, 0));\n input2Group.position.set(0.31, 0, 2.5);\n group.add(input2Group);\n }\n\n const input3Node = context.getENode(component.pins[3]!);\n if (input3Node) {\n const input3Group = this.createPinGroup(input3Node, 'right', new THREE.Euler(0.3, 0, 0));\n input3Group.position.set(-0.09, 0, 1.5);\n group.add(input3Group);\n }\n\n const input4Node = context.getENode(component.pins[4]!);\n if (input4Node) {\n const input4Group = this.createPinGroup(input4Node, 'right', new THREE.Euler(0.11, 0, 0));\n input4Group.position.set(-0.27, 0, 0.5);\n group.add(input4Group);\n }\n\n const input5Node = context.getENode(component.pins[5]!);\n if (input5Node) {\n const input5Group = this.createPinGroup(input5Node, 'right', new THREE.Euler(-0.11, 0, 0));\n input5Group.position.set(-0.27, 0, -0.5);\n group.add(input5Group);\n }\n\n const input6Node = context.getENode(component.pins[6]!);\n if (input6Node) {\n const input6Group = this.createPinGroup(input6Node, 'right', new THREE.Euler(-0.3, 0, 0));\n input6Group.position.set(-0.09, 0, -1.5);\n group.add(input6Group);\n }\n\n const input7Node = context.getENode(component.pins[7]!);\n if (input7Node) {\n const input7Group = this.createPinGroup(input7Node, 'right', new THREE.Euler(-0.53, 0, 0));\n input7Group.position.set(0.31, 0, -2.5);\n group.add(input7Group);\n }\n\n const input8Node = context.getENode(component.pins[8]!);\n if (input8Node) {\n const input8Group = this.createPinGroup(input8Node, 'right', new THREE.Euler(-0.7, 0, 0));\n input8Group.position.set(0.9, 0, -3.45);\n group.add(input8Group);\n }\n\n const outputNode = context.getENode(component.pins[9]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-1.39, 0, -0.05);\n group.add(outputGroup);\n }\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n Nor8GateVisualFactory.negativeMarkerGeometry,\n Nor8GateVisualFactory.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-0.8, 0.15, -2.7);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n}\n","import { ComponentVisualFactoryBase } from '../ComponentVisualFactory';\nimport {type Component, type ComponentState, type XorGateState} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport { OrGateGeometry, XorGateTailGeometry } from '../../utils/GeometryUtils';\nimport type { ConfigFormDefinition, VisualContext } from '../../types';\n\n/**\n * Visual factory for XOR gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class XorGateVisualFactory extends ComponentVisualFactoryBase {\n /** Gate high color */\n protected static readonly HIGH_COLOR = 0xffffff;\n /** Gate high emissive intensity */\n protected static readonly HIGH_INTENSITY = 0.3;\n /** XOR tail geometry */\n protected readonly tailGeometry = XorGateTailGeometry(1.5, 1.6, 0.8, 0.1, 0.8, 0.4, 16);\n /** Shared open envelope geometry */\n protected readonly lowGeometry = OrGateGeometry(1.5, 1.6, 0.1, 0.4, 16);\n /** Shared transient envelope geometry */\n protected readonly transientGeometry = OrGateGeometry(1.5, 1.6, 0.4, 0.4, 16);\n /** Shared transient envelope geometry */\n protected readonly highGeometry = OrGateGeometry(1.5, 1.6, 0.799, 0.4, 16);\n /** Shared material for negative marker **/\n protected readonly negativeMarkerMaterial = new THREE.MeshStandardMaterial({\n color: 0xfafafa,\n });\n /** Shared geometry for negative marker **/\n protected readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.2,\n 0.2,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override defaultRotation() {\n return Math.PI;\n }\n\n createVisual(component: Component, context: VisualContext): 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.4, 2, 1.8);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(XorGateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(0, 0.35, 0);\n group.add(envelope);\n\n //const tailMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n //tailMaterial.emissive.setHex(XorGateVisualFactory.HIGH_COLOR);\n //tailMaterial.emissiveIntensity = 0;\n const tail = new THREE.Mesh(this.tailGeometry, envelopeMaterial);\n tail.userData = {\n type: 'component',\n componentId: component.id,\n part: 'tail',\n };\n tail.rotateX(-Math.PI / 2);\n tail.rotateY(Math.PI);\n tail.position.set(-0.25, 0.35, 0);\n group.add(tail);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom');\n vccGroup.position.set(0.15, 0, 0.79);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[4]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top');\n gndGroup.position.set(0.15, 0, -0.79);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right', new THREE.Euler(0.45, 0, 0));\n input1Group.position.set(1.1, 0, 0.5);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right', new THREE.Euler(-0.45, 0, 0));\n input2Group.position.set(1.1, 0, -0.5);\n group.add(input2Group);\n }\n\n const outputNode = context.getENode(component.pins[3]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-0.7, 0, -0.05);\n group.add(outputGroup);\n }\n }\n\n /**\n * Get config form definition for XOR/XNOR Gate\n *\n * @param config - Optional current config to determine disabled state of transitionSpan\n * @returns Form definition with defaultLogicFamily dropdown, activationLogic boolean, and transitionSpan number\n */\n override getConfigFormDefinition(config?: Map<string, string>): ConfigFormDefinition | null {\n const logicFamily = config?.get('defaultLogicFamily') ?? 'CMOS1';\n return {\n fields: [\n {\n key: 'defaultLogicFamily',\n label: 'Logic Family',\n type: 'dropdown',\n options: { CMOS: 'CMOS1', TTL: 'TTL1', Sandbox: 'Sandbox' },\n },\n {\n key: 'activationLogic',\n label: 'Activation Logic',\n type: 'boolean',\n },\n {\n key: 'transitionSpan',\n label: 'Propagation delay (ticks)',\n type: 'number',\n min: 1,\n disabled: logicFamily !== 'Sandbox',\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\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 formData.set('defaultLogicFamily', config.get('defaultLogicFamily') ?? 'CMOS1');\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\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 config.set('defaultLogicFamily', formData.get('defaultLogicFamily') ?? 'CMOS1');\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 envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n this.negativeMarkerGeometry,\n this.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-0.7, 0.15, -0.6);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n\n /**\n * Update animation based on simulation state\n *\n * @param object3D - The Object3D created by createVisual()\n * @param state - The component 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 === 'high') {\n envelopeMesh.geometry = this.highGeometry;\n envelopeMesh.material.emissiveIntensity = XorGateVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = this.lowGeometry;\n envelopeMesh.material.emissiveIntensity = 0;\n }\n return;\n }\n\n const gateState = state as XorGateState;\n if (gateState.isHigh) {\n envelopeMesh.geometry = this.highGeometry;\n envelopeMesh.material.emissiveIntensity = XorGateVisualFactory.HIGH_INTENSITY;\n } else if (gateState.isInTransition) {\n envelopeMesh.geometry = this.transientGeometry;\n envelopeMesh.material.emissiveIntensity = 0.5 * XorGateVisualFactory.HIGH_INTENSITY;\n } else {\n envelopeMesh.geometry = this.lowGeometry;\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 protected 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 /**\n * Find the negative marker mesh within the component group\n *\n * @param object3D - The Object3D group created by createVisual()\n * @returns The negative marker mesh if found, null otherwise\n *\n * @remarks\n * Searches for a mesh with userData.part === 'negativeMarker'\n */\n protected findNegativeMarkerMesh(\n object3D: THREE.Object3D\n ): (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null {\n let negativeMarkerMesh: (THREE.Mesh & { material: THREE.MeshStandardMaterial }) | null = null;\n\n object3D.traverse((child) => {\n if (child instanceof THREE.Mesh && child.userData.part === 'negativeMarker') {\n if (child.material instanceof THREE.MeshStandardMaterial) {\n negativeMarkerMesh = child as THREE.Mesh & { material: THREE.MeshStandardMaterial };\n }\n }\n });\n return negativeMarkerMesh;\n }\n}\n","import {type Component} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport {OrGateGeometry, XorGateTailGeometry} from '../../utils/GeometryUtils';\nimport { XorGateVisualFactory } from './XorGateVisualFactory';\nimport type { VisualContext } from '../../types';\n\n/**\n * Visual factory for XOR gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class Xor4GateVisualFactory extends XorGateVisualFactory {\n /** XOR tail geometry */\n protected override readonly tailGeometry = XorGateTailGeometry(2, 3.6, 1.45, 0.13, 1.8, 0.4, 16);\n /** Shared open envelope geometry */\n protected override readonly lowGeometry = OrGateGeometry(2, 3.6, 0.13, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly transientGeometry = OrGateGeometry(2, 3.6, 0.23, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly highGeometry = OrGateGeometry(2, 3.6, 1, 0.4, 16);\n /** Shared geometry for negative marker **/\n protected override readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.25,\n 0.25,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override createVisual(component: Component, context: VisualContext): 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, 3, 2, 3.8);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(Xor4GateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(-0.25, 0.35, 0);\n group.add(envelope);\n\n const tail = new THREE.Mesh(this.tailGeometry, envelopeMaterial);\n tail.userData = {\n type: 'component',\n componentId: component.id,\n part: 'tail',\n };\n tail.rotateX(-Math.PI / 2);\n tail.rotateY(Math.PI);\n tail.position.set(-0.85, 0.35, 0);\n group.add(tail);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected override createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom', new THREE.Euler(0, 0, 0.23));\n vccGroup.position.set(0.15, 0, 1.73);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[6]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top',new THREE.Euler(0, 0, 0.23));\n gndGroup.position.set(0.15, 0, -1.73);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right', new THREE.Euler(0.6, 0, 0));\n input1Group.position.set(1.37, 0, 1.5);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right', new THREE.Euler(0.1, 0, 0));\n input2Group.position.set(0.93, 0, 0.5);\n group.add(input2Group);\n }\n\n const input3Node = context.getENode(component.pins[3]!);\n if (input3Node) {\n const input3Group = this.createPinGroup(input3Node, 'right', new THREE.Euler(-0.1, 0, 0));\n input3Group.position.set(0.93, 0, -0.5);\n group.add(input3Group);\n }\n\n const input4Node = context.getENode(component.pins[4]!);\n if (input4Node) {\n const input4Group = this.createPinGroup(input4Node, 'right', new THREE.Euler(-0.6, 0, 0));\n input4Group.position.set(1.37, 0, -1.5);\n group.add(input4Group);\n }\n\n const outputNode = context.getENode(component.pins[5]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-1.22, 0, 0);\n group.add(outputGroup);\n }\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n this.negativeMarkerGeometry,\n this.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-1, 0.15, -1.3);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n}\n","import {type Component} from 'simple-circuit-engine/core';\nimport * as THREE from 'three';\nimport {OrGateGeometry, XorGateTailGeometry} from '../../utils/GeometryUtils';\nimport { XorGateVisualFactory } from './XorGateVisualFactory';\nimport type { VisualContext } from '../../types';\n\n/**\n * Visual factory for XOR gates components\n *\n * Creates:\n * - Gate mesh\n * - vcc, gnd, inputs and output pin groups\n * - Component hitbox for raycasting\n *\n * Animation:\n * - Emissive glow when Gate is high (based on simulation state)\n */\nexport class Xor8GateVisualFactory extends XorGateVisualFactory {\n /** XOR tail geometry */\n protected override readonly tailGeometry = XorGateTailGeometry(2.6, 7.5, 2.4, 0.16, 3.5, 0.4, 16);\n /** Shared open envelope geometry */\n protected override readonly lowGeometry = OrGateGeometry(2.6, 7.5, 0.16, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly transientGeometry = OrGateGeometry(2.6, 7.5, 0.35, 0.4, 16);\n /** Shared transient envelope geometry */\n protected override readonly highGeometry = OrGateGeometry(2.6, 7.5, 1.3, 0.4, 16);\n /** Shared geometry for negative marker **/\n protected override readonly negativeMarkerGeometry = new THREE.CylinderGeometry(\n 0.35,\n 0.35,\n 0.4,\n 16,\n 4,\n false,\n 0,\n Math.PI * 2\n );\n\n override createVisual(component: Component, context: VisualContext): 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, 4, 2, 7.6);\n group.add(hitbox);\n\n // Visual Gate\n const envelopeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });\n envelopeMaterial.emissive.setHex(Xor8GateVisualFactory.HIGH_COLOR);\n envelopeMaterial.emissiveIntensity = 0;\n const envelope = new THREE.Mesh(this.lowGeometry, envelopeMaterial);\n envelope.userData = {\n type: 'component',\n componentId: component.id,\n part: 'envelope',\n initialState: 'low',\n };\n envelope.rotateX(-Math.PI / 2);\n envelope.rotateY(Math.PI);\n envelope.position.set(-0.45, 0.35, 0);\n group.add(envelope);\n\n const tail = new THREE.Mesh(this.tailGeometry, envelopeMaterial);\n tail.userData = {\n type: 'component',\n componentId: component.id,\n part: 'tail',\n };\n tail.rotateX(-Math.PI / 2);\n tail.rotateY(Math.PI);\n tail.position.set(-1.7, 0.35, 0);\n group.add(tail);\n\n // pins (not called if preview - no pins)\n if (component.pins.length > 0) {\n this.createPinsVisual(component, context, group);\n }\n\n this.updateFromConfiguration(group, component.config);\n return group;\n }\n\n protected override createPinsVisual(component: Component, context: VisualContext, group: THREE.Group) {\n const vccNode = context.getENode(component.pins[0]!);\n if (vccNode) {\n const vccGroup = this.createPinGroup(vccNode, 'bottom', new THREE.Euler(0, 0, 0.5));\n vccGroup.position.set(0.3, 0, 3.5);\n group.add(vccGroup);\n }\n\n const gndNode = context.getENode(component.pins[10]!);\n if (gndNode) {\n const gndGroup = this.createPinGroup(gndNode, 'top',new THREE.Euler(0, 0, 0.5));\n gndGroup.position.set(0.3, 0, -3.5);\n group.add(gndGroup);\n }\n\n const input1Node = context.getENode(component.pins[1]!);\n if (input1Node) {\n const input1Group = this.createPinGroup(input1Node, 'right', new THREE.Euler(0.7, 0, 0));\n input1Group.position.set(1.65, 0, 3.45);\n group.add(input1Group);\n }\n\n const input2Node = context.getENode(component.pins[2]!);\n if (input2Node) {\n const input2Group = this.createPinGroup(input2Node, 'right', new THREE.Euler(0.53, 0, 0));\n input2Group.position.set(1.09, 0, 2.5);\n group.add(input2Group);\n }\n\n const input3Node = context.getENode(component.pins[3]!);\n if (input3Node) {\n const input3Group = this.createPinGroup(input3Node, 'right', new THREE.Euler(0.3, 0, 0));\n input3Group.position.set(0.72, 0, 1.5);\n group.add(input3Group);\n }\n\n const input4Node = context.getENode(component.pins[4]!);\n if (input4Node) {\n const input4Group = this.createPinGroup(input4Node, 'right', new THREE.Euler(0.11, 0, 0));\n input4Group.position.set(0.54, 0, 0.5);\n group.add(input4Group);\n }\n\n const input5Node = context.getENode(component.pins[5]!);\n if (input5Node) {\n const input5Group = this.createPinGroup(input5Node, 'right', new THREE.Euler(-0.11, 0, 0));\n input5Group.position.set(0.54, 0, -0.5);\n group.add(input5Group);\n }\n\n const input6Node = context.getENode(component.pins[6]!);\n if (input6Node) {\n const input6Group = this.createPinGroup(input6Node, 'right', new THREE.Euler(-0.3, 0, 0));\n input6Group.position.set(0.72, 0, -1.5);\n group.add(input6Group);\n }\n\n const input7Node = context.getENode(component.pins[7]!);\n if (input7Node) {\n const input7Group = this.createPinGroup(input7Node, 'right', new THREE.Euler(-0.53, 0, 0));\n input7Group.position.set(1.1, 0, -2.5);\n group.add(input7Group);\n }\n\n const input8Node = context.getENode(component.pins[8]!);\n if (input8Node) {\n const input8Group = this.createPinGroup(input8Node, 'right', new THREE.Euler(-0.7, 0, 0));\n input8Group.position.set(1.7, 0, -3.45);\n group.add(input8Group);\n }\n\n const outputNode = context.getENode(component.pins[9]!);\n if (outputNode) {\n const outputGroup = this.createPinGroup(outputNode, 'left');\n outputGroup.position.set(-1.69, 0, 0);\n group.add(outputGroup);\n }\n }\n\n override updateFromConfiguration(object3D: THREE.Object3D, config: Map<string, string>) {\n const envelopeMesh = this.findEnvelopeMesh(object3D);\n if (!envelopeMesh) return;\n\n let negativeMarkerMesh = this.findNegativeMarkerMesh(object3D);\n\n if (config.get('activationLogic') === 'negative') {\n envelopeMesh.userData.initialState = 'high';\n if (!negativeMarkerMesh) {\n negativeMarkerMesh = new THREE.Mesh(\n this.negativeMarkerGeometry,\n this.negativeMarkerMaterial\n );\n negativeMarkerMesh.userData = {\n type: 'component',\n componentId: envelopeMesh.userData.componentId,\n part: 'negativeMarker',\n };\n\n negativeMarkerMesh.position.set(-1.02, 0.15, -2.86);\n object3D.add(negativeMarkerMesh);\n }\n } else {\n envelopeMesh.userData.initialState = 'low';\n if (negativeMarkerMesh) {\n object3D.remove(negativeMarkerMesh);\n }\n }\n this.updateAnimation(object3D, null);\n }\n}\n","import { ComponentType } from 'simple-circuit-engine/core';\nimport {\n type IGroupedFactoryRegistry,\n BatteryVisualFactory,\n LabelVisualFactory,\n LightbulbVisualFactory,\n RectangleLEDVisualFactory,\n RelayVisualFactory,\n SmallLEDVisualFactory,\n SwitchVisualFactory,\n DoubleThrowSwitchVisualFactory,\n InverterVisualFactory,\n NandGateVisualFactory,\n Nand4GateVisualFactory,\n Nand8GateVisualFactory,\n NorGateVisualFactory,\n Nor4GateVisualFactory,\n Nor8GateVisualFactory,\n XorGateVisualFactory,\n Xor4GateVisualFactory,\n Xor8GateVisualFactory\n} from './shared/components';\n\n/**\n * Register all basic components visual factories in the basic group\n * Basic components are : Battery, Label, Switches, Lightbulb, RectangleLED, Relay, SmallLED\n * @public\n * @param registry - A grouped factory registry to populate\n * @returns The input registry for chaining\n */\nexport function registerBasicComponentsFactories(\n registry: IGroupedFactoryRegistry\n): IGroupedFactoryRegistry {\n return registry.addGroup('basic', 'Basic Components', (group) =>\n group\n .add(ComponentType.Battery, new BatteryVisualFactory())\n .add(ComponentType.Label, new LabelVisualFactory())\n .add(ComponentType.Switch, new SwitchVisualFactory())\n .add(ComponentType.DoubleThrowSwitch, new DoubleThrowSwitchVisualFactory())\n .add(ComponentType.Lightbulb, new LightbulbVisualFactory())\n .add(ComponentType.RectangleLED, new RectangleLEDVisualFactory())\n .add(ComponentType.Relay, new RelayVisualFactory())\n .add(ComponentType.SmallLED, new SmallLEDVisualFactory())\n );\n}\n\n/**\n * Register all logic gates components visual factories in the gates group\n * gates are : Inverter, NAND (2,4,8 inputs), NOR (2,4,8 inputs) and XOR (2,4,8 inputs)\n * AND/OR are gotten by changing the activationLogic of NAND/NOR\n * @public\n * @param registry - A grouped factory registry to populate\n * @returns The input registry for chaining\n */\nexport function registerGatesComponentsFactories(\n registry: IGroupedFactoryRegistry\n): IGroupedFactoryRegistry {\n return registry.addGroup('gates', 'Logic Gates', (group) =>\n group\n .add(ComponentType.Inverter, new InverterVisualFactory())\n .add(ComponentType.NandGate, new NandGateVisualFactory())\n .add(ComponentType.Nand4Gate, new Nand4GateVisualFactory())\n .add(ComponentType.Nand8Gate, new Nand8GateVisualFactory())\n .add(ComponentType.NorGate, new NorGateVisualFactory())\n .add(ComponentType.Nor4Gate, new Nor4GateVisualFactory())\n .add(ComponentType.Nor8Gate, new Nor8GateVisualFactory())\n .add(ComponentType.XorGate, new XorGateVisualFactory())\n .add(ComponentType.Xor4Gate, new Xor4GateVisualFactory())\n .add(ComponentType.Xor8Gate, new Xor8GateVisualFactory())\n );\n}\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","depth","steps","shape","extrudeSettings","holePath","_AndGateTallGeometry","thickness","halfW","halfH","cx","radius","xComp","angle_top","innerHalfW","innerHalfH","cx_inner","radius_inner","xComp_inner","angle_top_inner","hole","AndGateGeometry","arcCenterX","_OrGateTallGeometry","backInset","u_b","cx_b","r_b","angle_b","backWallThickness","r_b_inner","inner_x_comp","angle_b_inner","inner_back_x","p","q","cx_r","radius_r","angle_top_r","OrGateGeometry","XorGateTailGeometry","orWidth","orHeight","tailWidth","barsSeparation","cx_b_tail","r_inner","x_outer_corner","x_flat","y3","y4","xInner","thetaInner","barsExist","capsExist","LGeometry","angle","invert","junctionRadius","t","alpha","halfAlpha","cosA","sinA","cotHalf","W","H","maxR","r","arcCX","outerCX","outerCY","CyclicTrapezoidGeometry","tailHeight","headHeight","halfTailH","halfHeadH","dH","L","innerTailHalfH","innerHeadHalfH","tipX","BRANCHING_POINT_SENTINEL","BRANCHING_POINT_GROUP","DEFAULT_WIDTH","DEFAULT_HEIGHT","OFFSET_X","OFFSET_Y","VIEWPORT_PADDING","ComponentPickerWidget","registry","onSelectionChange","onClose","firstGroup","screenPosition","header","title","closeBtn","e","groups","g","group","option","groupId","types","type","metadata","COMPONENT_TYPE_METADATA","label","value","item","isSelected","newValue","panelWidth","panelHeight","left","top","viewportWidth","viewportHeight","ev","maxLeft","maxTop","getNextSourceType","current","ENodeSourceType","BuildTool","controller","selection","container","controls","hoveredElement","previews","circuit","enodeId","componentId","wireId","screenPos","wire","nearestPoint","pos","worldPos","insertIndex","monoSelection","gridPosition","sourceEnodeId","enodeGroup","sourcePosition","previewWire","emit","targetEnodeId","hasSelected","targetWireId","targetType","pointIndex","originalPositions","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","snappedPosition","previousOverlap","tempEnode","ENode","ENodeType","factory","tempComponent","Component","child","cursorPos","mat","previewBox","componentObjects","_id","otherGroup","MIN_SELECTION_RECT_SIZE","MultiSelectTool","selectionManager","shiftHeld","circuitComponent","containerRect","screenX","screenY","startScreen","currentScreen","overlayElement","elementsInRect","newPreviewSet","id","screenRect","selectedEnodeIds","wireEnodeSelectionCount","componentObject3Ds","object3D","currentCount","enodeObject3Ds","count","components","enodes","wires","existing","totalCount","selectedIds","initialPositions","affectedWireIds","initialWireIntermediatePositions","dragStartWorld","delta","elementId","initialPos","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","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","hitboxGeom","coneGeometry","coneMaterial","newColor","state","fallbackEmissive","createLine2Material","linewidth","LineMaterial","WireVisualManager","wireObject3Ds","material","wirePath","line","geometry","LineGeometry","Line2","wireIdsToUpdate","currentMaterial","wireLines","_wireId","startPosition","previewLine","endPosition","componentGroup","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","nameOrDefault","bound","unhoverPreviousElement","element","hoverElement","previousElement","oldPosition","_event","_width","_height","Controller","parent","property","className","elementType","name","disabled","show","min","max","step","decimals","listen","curValue","BooleanController","normalizeColorString","string","match","STRING","v","INT","ARRAY","rgbScale","int","OBJECT","FORMATS","getColorFormat","format","ColorController","tryParse","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","closeFolders","injectStyles","touchStyles","$1","initialValue","folder","recursive","f","open","closed","initialHeight","onTransitionEnd","targetHeight","changedGUI","controllers","folders","ConfigPanelWidget","editComponentConfig","_camera","_domElement","formDef","PANEL_WIDTH","formData","key","field","changedKey","_value","formDataMap","coreConfig","CircuitController","_options","previousTool","tool","selected","_data","componentType","toolType","cursorType","mesh","pinGroup","defaultRotation","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","startupMode","mapControls","hoverManager","branchingPointVisualFactory","mode","previousMode","gridSize","gridDivisions","h","FactoryRegistry","fallbackFactory","ComponentVisualFactoryBase","_object3D","_config","direction","node","pointsTo","visualRotation","lockedSubtypes","smallSubtypes","userInfos","hitboxRadius","visualRadius","pinVisual","pinVisualRotation","source","_state","COLOR_PRESETS","isHexColor","hexToPresetOrHex","hex","lowerHex","presetHex","presetOrHexToHex","DefaultVisualFactory","boxGeometry","boxMaterial","box","hexColor","colorHex","ComponentGroupBuilder","_groupRecord","_factories","_typeToGroupId","_groups","existingGroupId","oldGroup","GroupedFactoryRegistry","builderCallback","groupRecord","builder","_type","_factory","BatteryVisualFactory","context","cylinderGeometry","cylinderMaterial","cylinder","cathodeNode","cathodeGroup","anodeNode","anodeGroup","LabelVisualFactory","_context","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","pin1Node","pin1Group","pin1Counterpart","pin2Node","pin2Group","pin2Counterpart","scale","bulbMesh","RectangleLEDVisualFactory","ledMaterial","ledGeometry","led","inputNode","outputNode","outputPinGroup","idleColor","activeColor","ledMesh","pin1","outputPin","idleColorHex","hwRatio","ywRatio","pinScale","RelayVisualFactory","coilGroup","contactorGroup","powerInBar","cmdOutNode","cmdOutGroup","cmdOutCounterpart","powerInNode","powerInGroup","powerInCounterpart","cmdInNode","cmdInGroup","cmdInCounterpart","powerOutNode","powerOutGroup","powerOutCounterpart","contactor","partsUserData","addCoil","z","xr","coil","bar","activationLogic","coilBar","negLog","gf","relayState","targetRotation","SmallLEDVisualFactory","SwitchVisualFactory","contactorGeometry","inputPinGroup","inputPinCounterpart","outputPinCounterpart","initialState","switchState","DoubleThrowSwitchVisualFactory","input1Node","input1PinGroup","input1PinCounterpart","input2Node","input2PinGroup","input2PinCounterpart","input3Node","input3PinGroup","input3PinCounterpart","InverterVisualFactory","vccNode","vccGroup","gndNode","gndGroup","inputGroup","outputGroup","oldEnvelope","envelope","envX","logicFamily","negativeMarkerMesh","vccVisual","gndVisual","envelopeMesh","isBuffer","lowGeometry","transientGeometry","highGeometry","bufferState","NandGateVisualFactory","envelopeMaterial","input1Group","input2Group","gateState","Nand4GateVisualFactory","input3Group","input4Node","input4Group","Nand8GateVisualFactory","input5Node","input5Group","input6Node","input6Group","input7Node","input7Group","input8Node","input8Group","NorGateVisualFactory","Nor4GateVisualFactory","Nor8GateVisualFactory","XorGateVisualFactory","tail","Xor4GateVisualFactory","Xor8GateVisualFactory","registerBasicComponentsFactories","registerGatesComponentsFactories"],"mappings":"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;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;AAuajB,SAASC,GAAeC,GAAa;AACpC,QAAMC,IAAW,SAA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","x_google_ignoreList":[17]}