force-3d-graph 1.2.3 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/force-3d-graph.js +666 -606
- package/dist/force-3d-graph.js.map +1 -1
- package/dist/force-3d-graph.umd.cjs +21 -21
- package/dist/force-3d-graph.umd.cjs.map +1 -1
- package/dist/index.d.ts +6 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"force-3d-graph.js","sources":["../src/utils/types.ts","../src/utils/ContainerManager.ts","../src/utils/validation.ts","../node_modules/three/examples/jsm/controls/OrbitControls.js","../src/core/SceneManager.ts","../src/core/NodeManager.ts","../src/core/EdgeManager.ts","../src/core/GraphEngine.ts","../src/core/RendererManager.ts","../src/factory/MaterialFactory.ts","../src/factory/NodeFactory.ts","../src/factory/EdgeFactory.ts","../src/performance/LODManager.ts","../src/performance/FrustumCuller.ts","../src/interaction/RaycasterManager.ts","../src/interaction/PanelManager.ts","../src/interaction/EdgePanelManager.ts","../src/interaction/EdgeTooltipManager.ts","../src/interaction/SearchManager.ts","../src/interaction/ViewToggleManager.ts","../src/core/ForceGraph2D.ts","../src/ForceGraph3D.ts","../src/test/sampleData.ts"],"sourcesContent":["// Global type declaration for __DEV__ flag\ndeclare const __DEV__: boolean;\n\n// ============================================================================\n// Data Interfaces (User-facing)\n// ============================================================================\n\n/**\n * Node data provided by the user\n */\nexport interface NodeData {\n /** Unique identifier for the node */\n id: string;\n /** Display label for the node */\n label: string;\n /** Optional hex color (default: 0x4A90E2) */\n color?: number;\n /** Optional initial position (random if not provided) */\n position?: Vector3Data;\n /** Additional custom data */\n [key: string]: unknown;\n}\n\n/**\n * Edge data provided by the user\n */\nexport interface Edge {\n /** Source node ID */\n source: string;\n /** Target node ID */\n target: string;\n /** Optional relationship label */\n relationship?: string;\n /** Additional custom data */\n [key: string]: unknown;\n}\n\n/**\n * Graph data structure\n */\nexport interface GraphData {\n nodes: NodeData[];\n edges: Edge[];\n}\n\n/**\n * Simple 3D vector\n */\nexport interface Vector3Data {\n x: number;\n y: number;\n z: number;\n}\n\n// ============================================================================\n// Internal Interfaces\n// ============================================================================\n\n/**\n * Internal node representation with physics state\n */\nexport interface InternalNode extends NodeData {\n position: Vector3Data;\n velocity: Vector3Data;\n mass: number;\n}\n\n/**\n * Internal edge representation\n */\nexport interface InternalEdge extends Edge {\n sourceNode: InternalNode;\n targetNode: InternalNode;\n}\n\n// ============================================================================\n// Configuration Interfaces\n// ============================================================================\n\n/**\n * Constructor options for ForceGraph3D\n */\nexport interface ForceGraph3DOptions {\n // Container element (optional - will create if not provided)\n container?: HTMLElement | null;\n\n // Scene configuration\n backgroundColor?: number | string;\n cameraPosition?: Vector3Data;\n cameraFov?: number;\n\n // Physics parameters\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n useBarnesHut?: boolean;\n barnesHutTheta?: number;\n\n // Node appearance\n defaultNodeColor?: number;\n nodeRadius?: number;\n nodeSegments?: number;\n\n // LOD configuration\n enableLOD?: boolean;\n lodDistances?: number[];\n lodSegments?: number[];\n\n // Edge appearance\n edgeColor?: number;\n edgeOpacity?: number;\n enableEdgeCulling?: boolean;\n\n // Panel configuration\n showPanel?: boolean;\n panelTemplate?: (nodeData: NodeData, neighbors: NodeData[]) => string;\n panelStyles?: Record<string, string>;\n\n // Search configuration\n showSearch?: boolean;\n searchPlaceholder?: string;\n\n // View mode configuration\n initialViewMode?: '2d' | '3d';\n showViewToggle?: boolean;\n\n // Performance\n targetFPS?: number;\n maxVisibleNodes?: number;\n\n // Event callbacks\n onNodeClick?: (nodeData: NodeData) => void;\n onNodeHover?: (nodeData: NodeData | null) => void;\n onEdgeHover?: (edge: Edge | null, sourceNode: NodeData | null, targetNode: NodeData | null) => void;\n onNodeAdd?: (nodeData: NodeData) => void;\n onNodeRemove?: (nodeId: string) => void;\n onEdgeAdd?: (edge: Edge) => void;\n onEdgeRemove?: (edge: Edge) => void;\n onExpand?: (nodeId: string, depth?: number) => Promise<GraphData>;\n}\n\n/**\n * Default options\n */\nexport const DEFAULT_OPTIONS: Required<Omit<ForceGraph3DOptions, 'container' | 'onNodeClick' | 'onNodeHover' | 'onEdgeHover' | 'onNodeAdd' | 'onNodeRemove' | 'onEdgeAdd' | 'onEdgeRemove' | 'onExpand' | 'panelTemplate' | 'panelStyles'>> = {\n backgroundColor: 0x0a0a0a,\n cameraPosition: { x: 0, y: 0, z: 80 },\n cameraFov: 75,\n\n repulsionStrength: 200,\n attractionStrength: 0.008,\n damping: 0.95,\n useBarnesHut: true, // Enabled by default for better performance\n barnesHutTheta: 0.5,\n\n defaultNodeColor: 0xff9966, // Tangerine to match the premium glass material\n nodeRadius: 2,\n nodeSegments: 32,\n\n enableLOD: true,\n lodDistances: [50, 100, 200],\n lodSegments: [32, 16, 8],\n\n edgeColor: 0x888888,\n edgeOpacity: 0.4,\n enableEdgeCulling: true,\n\n showPanel: true,\n showSearch: true,\n searchPlaceholder: 'Search nodes or relationships...',\n\n initialViewMode: '3d',\n showViewToggle: true,\n\n targetFPS: 60,\n maxVisibleNodes: 10000,\n};\n\n// ============================================================================\n// Event Types\n// ============================================================================\n\nexport type EventType =\n | 'nodeClick'\n | 'nodeHover'\n | 'edgeHover'\n | 'edgeClick'\n | 'nodeAdd'\n | 'nodeRemove'\n | 'edgeAdd'\n | 'edgeRemove'\n | 'expand'\n | 'viewChange'\n | 'ready';\n\nexport type EventCallback = (...args: unknown[]) => void;\n\n// ============================================================================\n// LOD Types\n// ============================================================================\n\nexport enum LODLevel {\n HIGH = 0,\n MEDIUM = 1,\n LOW = 2,\n}\n\n// ============================================================================\n// Three.js Object References\n// ============================================================================\n\nexport interface NodeObject {\n group: THREE.Group;\n sphere: THREE.Mesh;\n label: THREE.Sprite;\n lodLevel: LODLevel;\n}\n\nexport interface EdgeObject {\n line: THREE.Line;\n source: string;\n target: string;\n}\n\n// Import Three.js types for reference\nimport type * as THREE from 'three';\n","/**\n * Container management utility\n * Auto-creates a container div if none is provided\n */\n\nexport function createContainer(): HTMLElement {\n const container = document.createElement('div');\n container.id = 'force-graph-3d-container';\n container.style.cssText = `\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n overflow: hidden;\n `;\n document.body.appendChild(container);\n return container;\n}\n\nexport function validateContainer(container: HTMLElement | null | undefined): HTMLElement {\n if (container && container instanceof HTMLElement) {\n return container;\n }\n console.warn('[ForceGraph3D] No container provided, creating one automatically');\n return createContainer();\n}\n\nexport function getContainerDimensions(container: HTMLElement): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: rect.width || window.innerWidth,\n height: rect.height || window.innerHeight,\n };\n}\n","import type { NodeData, Edge } from './types';\n\n/**\n * Validates node data\n * @returns true if valid, false otherwise (logs warning)\n */\nexport function validateNodeData(node: unknown): node is NodeData {\n if (!node || typeof node !== 'object') {\n console.warn('[ForceGraph3D] Invalid node: must be an object');\n return false;\n }\n\n const n = node as Record<string, unknown>;\n\n if (typeof n.id !== 'string' || n.id.trim() === '') {\n console.warn('[ForceGraph3D] Invalid node: id must be a non-empty string');\n return false;\n }\n\n if (typeof n.label !== 'string') {\n console.warn('[ForceGraph3D] Invalid node: label must be a string');\n return false;\n }\n\n if (n.color !== undefined && typeof n.color !== 'number') {\n console.warn('[ForceGraph3D] Invalid node: color must be a number (hex)');\n return false;\n }\n\n if (n.position !== undefined) {\n if (!isValidPosition(n.position)) {\n console.warn('[ForceGraph3D] Invalid node: position must have x, y, z numbers');\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Validates edge data\n * @returns true if valid, false otherwise (logs warning)\n */\nexport function validateEdgeData(edge: unknown): edge is Edge {\n if (!edge || typeof edge !== 'object') {\n console.warn('[ForceGraph3D] Invalid edge: must be an object');\n return false;\n }\n\n const e = edge as Record<string, unknown>;\n\n if (typeof e.source !== 'string' || e.source.trim() === '') {\n console.warn('[ForceGraph3D] Invalid edge: source must be a non-empty string');\n return false;\n }\n\n if (typeof e.target !== 'string' || e.target.trim() === '') {\n console.warn('[ForceGraph3D] Invalid edge: target must be a non-empty string');\n return false;\n }\n\n return true;\n}\n\n/**\n * Validates a node ID\n */\nexport function validateNodeId(id: unknown): id is string {\n if (typeof id !== 'string' || id.trim() === '') {\n console.warn('[ForceGraph3D] Invalid node ID: must be a non-empty string');\n return false;\n }\n return true;\n}\n\n/**\n * Validates a position object\n */\nfunction isValidPosition(pos: unknown): pos is { x: number; y: number; z: number } {\n if (!pos || typeof pos !== 'object') return false;\n const p = pos as Record<string, unknown>;\n return (\n typeof p.x === 'number' &&\n typeof p.y === 'number' &&\n typeof p.z === 'number'\n );\n}\n\n/**\n * Creates a normalized edge key for duplicate detection\n * Always puts the smaller ID first to handle bidirectional edges\n */\nexport function createEdgeKey(source: string, target: string): string {\n // For self-loops, just use the single ID\n if (source === target) {\n return `${source}-${target}`;\n }\n // Normalize direction for duplicate detection\n return source < target ? `${source}-${target}` : `${target}-${source}`;\n}\n","import {\n\tEventDispatcher,\n\tMOUSE,\n\tQuaternion,\n\tSpherical,\n\tTOUCH,\n\tVector2,\n\tVector3,\n\tPlane,\n\tRay,\n\tMathUtils\n} from 'three';\n\n// OrbitControls performs orbiting, dollying (zooming), and panning.\n// Unlike TrackballControls, it maintains the \"up\" direction object.up (+Y by default).\n//\n// Orbit - left mouse / touch: one-finger move\n// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish\n// Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move\n\nconst _changeEvent = { type: 'change' };\nconst _startEvent = { type: 'start' };\nconst _endEvent = { type: 'end' };\nconst _ray = new Ray();\nconst _plane = new Plane();\nconst TILT_LIMIT = Math.cos( 70 * MathUtils.DEG2RAD );\n\nclass OrbitControls extends EventDispatcher {\n\n\tconstructor( object, domElement ) {\n\n\t\tsuper();\n\n\t\tthis.object = object;\n\t\tthis.domElement = domElement;\n\t\tthis.domElement.style.touchAction = 'none'; // disable touch scroll\n\n\t\t// Set to false to disable this control\n\t\tthis.enabled = true;\n\n\t\t// \"target\" sets the location of focus, where the object orbits around\n\t\tthis.target = new Vector3();\n\n\t\t// Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect\n\t\tthis.cursor = new Vector3();\n\n\t\t// How far you can dolly in and out ( PerspectiveCamera only )\n\t\tthis.minDistance = 0;\n\t\tthis.maxDistance = Infinity;\n\n\t\t// How far you can zoom in and out ( OrthographicCamera only )\n\t\tthis.minZoom = 0;\n\t\tthis.maxZoom = Infinity;\n\n\t\t// Limit camera target within a spherical area around the cursor\n\t\tthis.minTargetRadius = 0;\n\t\tthis.maxTargetRadius = Infinity;\n\n\t\t// How far you can orbit vertically, upper and lower limits.\n\t\t// Range is 0 to Math.PI radians.\n\t\tthis.minPolarAngle = 0; // radians\n\t\tthis.maxPolarAngle = Math.PI; // radians\n\n\t\t// How far you can orbit horizontally, upper and lower limits.\n\t\t// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )\n\t\tthis.minAzimuthAngle = - Infinity; // radians\n\t\tthis.maxAzimuthAngle = Infinity; // radians\n\n\t\t// Set to true to enable damping (inertia)\n\t\t// If damping is enabled, you must call controls.update() in your animation loop\n\t\tthis.enableDamping = false;\n\t\tthis.dampingFactor = 0.05;\n\n\t\t// This option actually enables dollying in and out; left as \"zoom\" for backwards compatibility.\n\t\t// Set to false to disable zooming\n\t\tthis.enableZoom = true;\n\t\tthis.zoomSpeed = 1.0;\n\n\t\t// Set to false to disable rotating\n\t\tthis.enableRotate = true;\n\t\tthis.rotateSpeed = 1.0;\n\n\t\t// Set to false to disable panning\n\t\tthis.enablePan = true;\n\t\tthis.panSpeed = 1.0;\n\t\tthis.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up\n\t\tthis.keyPanSpeed = 7.0;\t// pixels moved per arrow key push\n\t\tthis.zoomToCursor = false;\n\n\t\t// Set to true to automatically rotate around the target\n\t\t// If auto-rotate is enabled, you must call controls.update() in your animation loop\n\t\tthis.autoRotate = false;\n\t\tthis.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60\n\n\t\t// The four arrow keys\n\t\tthis.keys = { LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' };\n\n\t\t// Mouse buttons\n\t\tthis.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };\n\n\t\t// Touch fingers\n\t\tthis.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };\n\n\t\t// for reset\n\t\tthis.target0 = this.target.clone();\n\t\tthis.position0 = this.object.position.clone();\n\t\tthis.zoom0 = this.object.zoom;\n\n\t\t// the target DOM element for key events\n\t\tthis._domElementKeyEvents = null;\n\n\t\t//\n\t\t// public methods\n\t\t//\n\n\t\tthis.getPolarAngle = function () {\n\n\t\t\treturn spherical.phi;\n\n\t\t};\n\n\t\tthis.getAzimuthalAngle = function () {\n\n\t\t\treturn spherical.theta;\n\n\t\t};\n\n\t\tthis.getDistance = function () {\n\n\t\t\treturn this.object.position.distanceTo( this.target );\n\n\t\t};\n\n\t\tthis.listenToKeyEvents = function ( domElement ) {\n\n\t\t\tdomElement.addEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = domElement;\n\n\t\t};\n\n\t\tthis.stopListenToKeyEvents = function () {\n\n\t\t\tthis._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = null;\n\n\t\t};\n\n\t\tthis.saveState = function () {\n\n\t\t\tscope.target0.copy( scope.target );\n\t\t\tscope.position0.copy( scope.object.position );\n\t\t\tscope.zoom0 = scope.object.zoom;\n\n\t\t};\n\n\t\tthis.reset = function () {\n\n\t\t\tscope.target.copy( scope.target0 );\n\t\t\tscope.object.position.copy( scope.position0 );\n\t\t\tscope.object.zoom = scope.zoom0;\n\n\t\t\tscope.object.updateProjectionMatrix();\n\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\tscope.update();\n\n\t\t\tstate = STATE.NONE;\n\n\t\t};\n\n\t\t// this method is exposed, but perhaps it would be better if we can make it private...\n\t\tthis.update = function () {\n\n\t\t\tconst offset = new Vector3();\n\n\t\t\t// so camera.up is the orbit axis\n\t\t\tconst quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) );\n\t\t\tconst quatInverse = quat.clone().invert();\n\n\t\t\tconst lastPosition = new Vector3();\n\t\t\tconst lastQuaternion = new Quaternion();\n\t\t\tconst lastTargetPosition = new Vector3();\n\n\t\t\tconst twoPI = 2 * Math.PI;\n\n\t\t\treturn function update( deltaTime = null ) {\n\n\t\t\t\tconst position = scope.object.position;\n\n\t\t\t\toffset.copy( position ).sub( scope.target );\n\n\t\t\t\t// rotate offset to \"y-axis-is-up\" space\n\t\t\t\toffset.applyQuaternion( quat );\n\n\t\t\t\t// angle from z-axis around y-axis\n\t\t\t\tspherical.setFromVector3( offset );\n\n\t\t\t\tif ( scope.autoRotate && state === STATE.NONE ) {\n\n\t\t\t\t\trotateLeft( getAutoRotationAngle( deltaTime ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( scope.enableDamping ) {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta * scope.dampingFactor;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi * scope.dampingFactor;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi;\n\n\t\t\t\t}\n\n\t\t\t\t// restrict theta to be between desired limits\n\n\t\t\t\tlet min = scope.minAzimuthAngle;\n\t\t\t\tlet max = scope.maxAzimuthAngle;\n\n\t\t\t\tif ( isFinite( min ) && isFinite( max ) ) {\n\n\t\t\t\t\tif ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI;\n\n\t\t\t\t\tif ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI;\n\n\t\t\t\t\tif ( min <= max ) {\n\n\t\t\t\t\t\tspherical.theta = Math.max( min, Math.min( max, spherical.theta ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tspherical.theta = ( spherical.theta > ( min + max ) / 2 ) ?\n\t\t\t\t\t\t\tMath.max( min, spherical.theta ) :\n\t\t\t\t\t\t\tMath.min( max, spherical.theta );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// restrict phi to be between desired limits\n\t\t\t\tspherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );\n\n\t\t\t\tspherical.makeSafe();\n\n\n\t\t\t\t// move target to panned location\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tscope.target.addScaledVector( panOffset, scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tscope.target.add( panOffset );\n\n\t\t\t\t}\n\n\t\t\t\t// Limit the target distance from the cursor to create a sphere around the center of interest\n\t\t\t\tscope.target.sub( scope.cursor );\n\t\t\t\tscope.target.clampLength( scope.minTargetRadius, scope.maxTargetRadius );\n\t\t\t\tscope.target.add( scope.cursor );\n\n\t\t\t\t// adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera\n\t\t\t\t// we adjust zoom later in these cases\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius * scale );\n\n\t\t\t\t}\n\n\t\t\t\toffset.setFromSpherical( spherical );\n\n\t\t\t\t// rotate offset back to \"camera-up-vector-is-up\" space\n\t\t\t\toffset.applyQuaternion( quatInverse );\n\n\t\t\t\tposition.copy( scope.target ).add( offset );\n\n\t\t\t\tscope.object.lookAt( scope.target );\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tsphericalDelta.theta *= ( 1 - scope.dampingFactor );\n\t\t\t\t\tsphericalDelta.phi *= ( 1 - scope.dampingFactor );\n\n\t\t\t\t\tpanOffset.multiplyScalar( 1 - scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsphericalDelta.set( 0, 0, 0 );\n\n\t\t\t\t\tpanOffset.set( 0, 0, 0 );\n\n\t\t\t\t}\n\n\t\t\t\t// adjust camera position\n\t\t\t\tlet zoomChanged = false;\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom ) {\n\n\t\t\t\t\tlet newRadius = null;\n\t\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t\t// move the camera down the pointer ray\n\t\t\t\t\t\t// this method avoids floating point error\n\t\t\t\t\t\tconst prevRadius = offset.length();\n\t\t\t\t\t\tnewRadius = clampDistance( prevRadius * scale );\n\n\t\t\t\t\t\tconst radiusDelta = prevRadius - newRadius;\n\t\t\t\t\t\tscope.object.position.addScaledVector( dollyDirection, radiusDelta );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t\t// adjust the ortho camera position based on zoom changes\n\t\t\t\t\t\tconst mouseBefore = new Vector3( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseBefore.unproject( scope.object );\n\n\t\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\t\t\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\t\t\tzoomChanged = true;\n\n\t\t\t\t\t\tconst mouseAfter = new Vector3( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseAfter.unproject( scope.object );\n\n\t\t\t\t\t\tscope.object.position.sub( mouseAfter ).add( mouseBefore );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t\tnewRadius = offset.length();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.' );\n\t\t\t\t\t\tscope.zoomToCursor = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// handle the placement of the target\n\t\t\t\t\tif ( newRadius !== null ) {\n\n\t\t\t\t\t\tif ( this.screenSpacePanning ) {\n\n\t\t\t\t\t\t\t// position the orbit target in front of the new camera position\n\t\t\t\t\t\t\tscope.target.set( 0, 0, - 1 )\n\t\t\t\t\t\t\t\t.transformDirection( scope.object.matrix )\n\t\t\t\t\t\t\t\t.multiplyScalar( newRadius )\n\t\t\t\t\t\t\t\t.add( scope.object.position );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// get the ray and translation plane to compute target\n\t\t\t\t\t\t\t_ray.origin.copy( scope.object.position );\n\t\t\t\t\t\t\t_ray.direction.set( 0, 0, - 1 ).transformDirection( scope.object.matrix );\n\n\t\t\t\t\t\t\t// if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid\n\t\t\t\t\t\t\t// extremely large values\n\t\t\t\t\t\t\tif ( Math.abs( scope.object.up.dot( _ray.direction ) ) < TILT_LIMIT ) {\n\n\t\t\t\t\t\t\t\tobject.lookAt( scope.target );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t_plane.setFromNormalAndCoplanarPoint( scope.object.up, scope.target );\n\t\t\t\t\t\t\t\t_ray.intersectPlane( _plane, scope.target );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\t\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\t\tzoomChanged = true;\n\n\t\t\t\t}\n\n\t\t\t\tscale = 1;\n\t\t\t\tperformCursorZoom = false;\n\n\t\t\t\t// update condition is:\n\t\t\t\t// min(camera displacement, camera rotation in radians)^2 > EPS\n\t\t\t\t// using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n\t\t\t\tif ( zoomChanged ||\n\t\t\t\t\tlastPosition.distanceToSquared( scope.object.position ) > EPS ||\n\t\t\t\t\t8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ||\n\t\t\t\t\tlastTargetPosition.distanceToSquared( scope.target ) > 0 ) {\n\n\t\t\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\t\t\tlastPosition.copy( scope.object.position );\n\t\t\t\t\tlastQuaternion.copy( scope.object.quaternion );\n\t\t\t\t\tlastTargetPosition.copy( scope.target );\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t};\n\n\t\t}();\n\n\t\tthis.dispose = function () {\n\n\t\t\tscope.domElement.removeEventListener( 'contextmenu', onContextMenu );\n\n\t\t\tscope.domElement.removeEventListener( 'pointerdown', onPointerDown );\n\t\t\tscope.domElement.removeEventListener( 'pointercancel', onPointerUp );\n\t\t\tscope.domElement.removeEventListener( 'wheel', onMouseWheel );\n\n\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\n\t\t\tif ( scope._domElementKeyEvents !== null ) {\n\n\t\t\t\tscope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\t\tscope._domElementKeyEvents = null;\n\n\t\t\t}\n\n\t\t\t//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?\n\n\t\t};\n\n\t\t//\n\t\t// internals\n\t\t//\n\n\t\tconst scope = this;\n\n\t\tconst STATE = {\n\t\t\tNONE: - 1,\n\t\t\tROTATE: 0,\n\t\t\tDOLLY: 1,\n\t\t\tPAN: 2,\n\t\t\tTOUCH_ROTATE: 3,\n\t\t\tTOUCH_PAN: 4,\n\t\t\tTOUCH_DOLLY_PAN: 5,\n\t\t\tTOUCH_DOLLY_ROTATE: 6\n\t\t};\n\n\t\tlet state = STATE.NONE;\n\n\t\tconst EPS = 0.000001;\n\n\t\t// current position in spherical coordinates\n\t\tconst spherical = new Spherical();\n\t\tconst sphericalDelta = new Spherical();\n\n\t\tlet scale = 1;\n\t\tconst panOffset = new Vector3();\n\n\t\tconst rotateStart = new Vector2();\n\t\tconst rotateEnd = new Vector2();\n\t\tconst rotateDelta = new Vector2();\n\n\t\tconst panStart = new Vector2();\n\t\tconst panEnd = new Vector2();\n\t\tconst panDelta = new Vector2();\n\n\t\tconst dollyStart = new Vector2();\n\t\tconst dollyEnd = new Vector2();\n\t\tconst dollyDelta = new Vector2();\n\n\t\tconst dollyDirection = new Vector3();\n\t\tconst mouse = new Vector2();\n\t\tlet performCursorZoom = false;\n\n\t\tconst pointers = [];\n\t\tconst pointerPositions = {};\n\n\t\tlet controlActive = false;\n\n\t\tfunction getAutoRotationAngle( deltaTime ) {\n\n\t\t\tif ( deltaTime !== null ) {\n\n\t\t\t\treturn ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime;\n\n\t\t\t} else {\n\n\t\t\t\treturn 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getZoomScale( delta ) {\n\n\t\t\tconst normalizedDelta = Math.abs( delta * 0.01 );\n\t\t\treturn Math.pow( 0.95, scope.zoomSpeed * normalizedDelta );\n\n\t\t}\n\n\t\tfunction rotateLeft( angle ) {\n\n\t\t\tsphericalDelta.theta -= angle;\n\n\t\t}\n\n\t\tfunction rotateUp( angle ) {\n\n\t\t\tsphericalDelta.phi -= angle;\n\n\t\t}\n\n\t\tconst panLeft = function () {\n\n\t\t\tconst v = new Vector3();\n\n\t\t\treturn function panLeft( distance, objectMatrix ) {\n\n\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix\n\t\t\t\tv.multiplyScalar( - distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\tconst panUp = function () {\n\n\t\t\tconst v = new Vector3();\n\n\t\t\treturn function panUp( distance, objectMatrix ) {\n\n\t\t\t\tif ( scope.screenSpacePanning === true ) {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 1 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 );\n\t\t\t\t\tv.crossVectors( scope.object.up, v );\n\n\t\t\t\t}\n\n\t\t\t\tv.multiplyScalar( distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\t// deltaX and deltaY are in pixels; right and down are positive\n\t\tconst pan = function () {\n\n\t\t\tconst offset = new Vector3();\n\n\t\t\treturn function pan( deltaX, deltaY ) {\n\n\t\t\t\tconst element = scope.domElement;\n\n\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t// perspective\n\t\t\t\t\tconst position = scope.object.position;\n\t\t\t\t\toffset.copy( position ).sub( scope.target );\n\t\t\t\t\tlet targetDistance = offset.length();\n\n\t\t\t\t\t// half of the fov is center to top of screen\n\t\t\t\t\ttargetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );\n\n\t\t\t\t\t// we use only clientHeight here so aspect ratio does not distort speed\n\t\t\t\t\tpanLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );\n\t\t\t\t\tpanUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t// orthographic\n\t\t\t\t\tpanLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );\n\t\t\t\t\tpanUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// camera neither orthographic nor perspective\n\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );\n\t\t\t\t\tscope.enablePan = false;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}();\n\n\t\tfunction dollyOut( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale /= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction dollyIn( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale *= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction updateZoomParameters( x, y ) {\n\n\t\t\tif ( ! scope.zoomToCursor ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tperformCursorZoom = true;\n\n\t\t\tconst rect = scope.domElement.getBoundingClientRect();\n\t\t\tconst dx = x - rect.left;\n\t\t\tconst dy = y - rect.top;\n\t\t\tconst w = rect.width;\n\t\t\tconst h = rect.height;\n\n\t\t\tmouse.x = ( dx / w ) * 2 - 1;\n\t\t\tmouse.y = - ( dy / h ) * 2 + 1;\n\n\t\t\tdollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize();\n\n\t\t}\n\n\t\tfunction clampDistance( dist ) {\n\n\t\t\treturn Math.max( scope.minDistance, Math.min( scope.maxDistance, dist ) );\n\n\t\t}\n\n\t\t//\n\t\t// event callbacks - update the object state\n\t\t//\n\n\t\tfunction handleMouseDownRotate( event ) {\n\n\t\t\trotateStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownDolly( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientX );\n\t\t\tdollyStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownPan( event ) {\n\n\t\t\tpanStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseMoveRotate( event ) {\n\n\t\t\trotateEnd.set( event.clientX, event.clientY );\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMoveDolly( event ) {\n\n\t\t\tdollyEnd.set( event.clientX, event.clientY );\n\n\t\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( dollyDelta.y ) );\n\n\t\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( dollyDelta.y ) );\n\n\t\t\t}\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMovePan( event ) {\n\n\t\t\tpanEnd.set( event.clientX, event.clientY );\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseWheel( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientY );\n\n\t\t\tif ( event.deltaY < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( event.deltaY ) );\n\n\t\t\t} else if ( event.deltaY > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( event.deltaY ) );\n\n\t\t\t}\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleKeyDown( event ) {\n\n\t\t\tlet needsUpdate = false;\n\n\t\t\tswitch ( event.code ) {\n\n\t\t\t\tcase scope.keys.UP:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.BOTTOM:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, - scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.LEFT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.RIGHT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( - scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( needsUpdate ) {\n\n\t\t\t\t// prevent the browser from scrolling on cursor keys\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\tscope.update();\n\n\t\t\t}\n\n\n\t\t}\n\n\t\tfunction handleTouchStartRotate( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\trotateStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartPan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyStart.set( 0, distance );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchStartPan( event );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchStartRotate( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveRotate( event ) {\n\n\t\t\tif ( pointers.length == 1 ) {\n\n\t\t\t\trotateEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMovePan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyEnd.set( 0, distance );\n\n\t\t\tdollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );\n\n\t\t\tdollyOut( dollyDelta.y );\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tconst centerX = ( event.pageX + position.x ) * 0.5;\n\t\t\tconst centerY = ( event.pageY + position.y ) * 0.5;\n\n\t\t\tupdateZoomParameters( centerX, centerY );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchMovePan( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchMoveRotate( event );\n\n\t\t}\n\n\t\t//\n\t\t// event handlers - FSM: listen for events and reset state\n\t\t//\n\n\t\tfunction onPointerDown( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( pointers.length === 0 ) {\n\n\t\t\t\tscope.domElement.setPointerCapture( event.pointerId );\n\n\t\t\t\tscope.domElement.addEventListener( 'pointermove', onPointerMove );\n\t\t\t\tscope.domElement.addEventListener( 'pointerup', onPointerUp );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\taddPointer( event );\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchStart( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseDown( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerMove( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchMove( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseMove( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerUp( event ) {\n\n\t\t\tremovePointer( event );\n\n\t\t\tif ( pointers.length === 0 ) {\n\n\t\t\t\tscope.domElement.releasePointerCapture( event.pointerId );\n\n\t\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\t\t\t}\n\n\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t\tstate = STATE.NONE;\n\n\t\t}\n\n\t\tfunction onMouseDown( event ) {\n\n\t\t\tlet mouseAction;\n\n\t\t\tswitch ( event.button ) {\n\n\t\t\t\tcase 0:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.LEFT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.MIDDLE;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.RIGHT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tmouseAction = - 1;\n\n\t\t\t}\n\n\t\t\tswitch ( mouseAction ) {\n\n\t\t\t\tcase MOUSE.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseDownDolly( event );\n\n\t\t\t\t\tstate = STATE.DOLLY;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MOUSE.ROTATE:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MOUSE.PAN:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseMove( event ) {\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleMouseMoveRotate( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseMoveDolly( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleMouseMovePan( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseWheel( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\thandleMouseWheel( customWheelEvent( event ) );\n\n\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t}\n\n\t\tfunction customWheelEvent( event ) {\n\n\t\t\tconst mode = event.deltaMode;\n\n\t\t\t// minimal wheel event altered to meet delta-zoom demand\n\t\t\tconst newEvent = {\n\t\t\t\tclientX: event.clientX,\n\t\t\t\tclientY: event.clientY,\n\t\t\t\tdeltaY: event.deltaY,\n\t\t\t}\n\n\t\t\tswitch ( mode ) {\n\n\t\t\t\tcase 1: // LINE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 16;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2: // PAGE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 100;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\t// detect if event was triggered by pinching\n\t\t\tif ( event.ctrlKey && !controlActive ) {\n\n\t\t\t\tnewEvent.deltaY *= 10;\n\n\t\t\t}\n\n\t\t\treturn newEvent;\n\n\t\t}\n\n\t\tfunction interceptControlDown( event ) {\n\n\t\t\tif ( event.key === \"Control\" ) {\n\n\t\t\t\tcontrolActive = true;\n\t\t\t\t\n\t\t\t\tdocument.addEventListener('keyup', interceptControlUp, { passive: true, capture: true });\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction interceptControlUp( event ) {\n\n\t\t\tif ( event.key === \"Control\" ) {\n\n\t\t\t\tcontrolActive = false;\n\t\t\t\t\n\t\t\t\tdocument.removeEventListener('keyup', interceptControlUp, { passive: true, capture: true });\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onKeyDown( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enablePan === false ) return;\n\n\t\t\thandleKeyDown( event );\n\n\t\t}\n\n\t\tfunction onTouchStart( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( pointers.length ) {\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tswitch ( scope.touches.ONE ) {\n\n\t\t\t\t\t\tcase TOUCH.ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase TOUCH.PAN:\n\n\t\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tswitch ( scope.touches.TWO ) {\n\n\t\t\t\t\t\tcase TOUCH.DOLLY_PAN:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase TOUCH.DOLLY_ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onTouchMove( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.TOUCH_ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMovePan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_PAN:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyPan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_ROTATE:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onContextMenu( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t}\n\n\t\tfunction addPointer( event ) {\n\n\t\t\tpointers.push( event.pointerId );\n\n\t\t}\n\n\t\tfunction removePointer( event ) {\n\n\t\t\tdelete pointerPositions[ event.pointerId ];\n\n\t\t\tfor ( let i = 0; i < pointers.length; i ++ ) {\n\n\t\t\t\tif ( pointers[ i ] == event.pointerId ) {\n\n\t\t\t\t\tpointers.splice( i, 1 );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction trackPointer( event ) {\n\n\t\t\tlet position = pointerPositions[ event.pointerId ];\n\n\t\t\tif ( position === undefined ) {\n\n\t\t\t\tposition = new Vector2();\n\t\t\t\tpointerPositions[ event.pointerId ] = position;\n\n\t\t\t}\n\n\t\t\tposition.set( event.pageX, event.pageY );\n\n\t\t}\n\n\t\tfunction getSecondPointerPosition( event ) {\n\n\t\t\tconst pointerId = ( event.pointerId === pointers[ 0 ] ) ? pointers[ 1 ] : pointers[ 0 ];\n\n\t\t\treturn pointerPositions[ pointerId ];\n\n\t\t}\n\n\t\t//\n\n\t\tscope.domElement.addEventListener( 'contextmenu', onContextMenu );\n\n\t\tscope.domElement.addEventListener( 'pointerdown', onPointerDown );\n\t\tscope.domElement.addEventListener( 'pointercancel', onPointerUp );\n\t\tscope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } );\n\n\t\tdocument.addEventListener( 'keydown', interceptControlDown, { passive: true, capture: true } );\n\n\t\t// force an update at start\n\n\t\tthis.update();\n\n\t}\n\n}\n\nexport { OrbitControls };","import * as THREE from 'three';\nimport { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';\nimport type { ForceGraph3DOptions, Vector3Data } from '../utils/types';\nimport { getContainerDimensions } from '../utils/ContainerManager';\n\n/**\n * Scene Manager\n * Handles Three.js scene setup, camera, renderer, and controls\n */\nexport class SceneManager {\n public scene: THREE.Scene;\n public camera: THREE.PerspectiveCamera;\n public renderer: THREE.WebGLRenderer;\n public controls: OrbitControls;\n\n private container: HTMLElement;\n private resizeHandler: () => void;\n\n constructor(container: HTMLElement, options: ForceGraph3DOptions) {\n this.container = container;\n\n // Create scene\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(\n options.backgroundColor ?? 0x0a0a0a\n );\n\n // Create camera\n const { width, height } = getContainerDimensions(container);\n const fov = options.cameraFov ?? 75;\n this.camera = new THREE.PerspectiveCamera(fov, width / height, 0.1, 2000);\n\n const camPos = options.cameraPosition ?? { x: 0, y: 0, z: 80 };\n this.camera.position.set(camPos.x, camPos.y, camPos.z);\n\n // Create renderer with high quality settings\n this.renderer = new THREE.WebGLRenderer({\n antialias: true,\n alpha: true,\n powerPreference: 'high-performance',\n });\n this.renderer.setSize(width, height);\n this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));\n this.renderer.toneMapping = THREE.ACESFilmicToneMapping;\n this.renderer.toneMappingExposure = 1.0;\n this.renderer.shadowMap.enabled = true;\n this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;\n\n container.appendChild(this.renderer.domElement);\n\n // Create orbit controls\n this.controls = new OrbitControls(this.camera, this.renderer.domElement);\n this.controls.enableDamping = true;\n this.controls.dampingFactor = 0.05;\n this.controls.rotateSpeed = 0.8;\n this.controls.zoomSpeed = 1.2;\n this.controls.minDistance = 10;\n this.controls.maxDistance = 500;\n\n // Setup lighting\n this.setupLighting();\n\n // Handle resize\n this.resizeHandler = this.onWindowResize.bind(this);\n window.addEventListener('resize', this.resizeHandler);\n }\n\n /**\n * Sets up scene lighting for gradient glass on dark background\n */\n private setupLighting(): void {\n // Moderate ambient light for dark environment\n const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);\n this.scene.add(ambientLight);\n\n // Main key light from top-right\n const keyLight = new THREE.DirectionalLight(0xffffff, 0.9);\n keyLight.position.set(50, 60, 40);\n keyLight.castShadow = true;\n keyLight.shadow.mapSize.width = 1024;\n keyLight.shadow.mapSize.height = 1024;\n this.scene.add(keyLight);\n\n // Fill light from opposite side\n const fillLight = new THREE.DirectionalLight(0xfff0e0, 0.4);\n fillLight.position.set(-50, 30, -40);\n this.scene.add(fillLight);\n\n // Rim light for edge highlights\n const rimLight = new THREE.DirectionalLight(0xffffff, 0.3);\n rimLight.position.set(0, -30, -50);\n this.scene.add(rimLight);\n\n // Tangerine accent light\n const accentLight1 = new THREE.PointLight(0xff9966, 0.5, 150);\n accentLight1.position.set(40, 20, 40);\n this.scene.add(accentLight1);\n\n // Warm accent light\n const accentLight2 = new THREE.PointLight(0xffcc99, 0.4, 150);\n accentLight2.position.set(-40, -20, 40);\n this.scene.add(accentLight2);\n\n // Cool blue accent for contrast\n const accentLight3 = new THREE.PointLight(0x6699ff, 0.2, 100);\n accentLight3.position.set(0, 40, -40);\n this.scene.add(accentLight3);\n }\n\n /**\n * Handle window resize\n */\n private onWindowResize(): void {\n const { width, height } = getContainerDimensions(this.container);\n\n this.camera.aspect = width / height;\n this.camera.updateProjectionMatrix();\n\n this.renderer.setSize(width, height);\n }\n\n /**\n * Adds an object to the scene\n */\n add(object: THREE.Object3D): void {\n this.scene.add(object);\n }\n\n /**\n * Removes an object from the scene\n */\n remove(object: THREE.Object3D): void {\n this.scene.remove(object);\n }\n\n /**\n * Renders the scene\n */\n render(): void {\n this.controls.update();\n this.renderer.render(this.scene, this.camera);\n }\n\n /**\n * Gets the camera position\n */\n getCameraPosition(): Vector3Data {\n return {\n x: this.camera.position.x,\n y: this.camera.position.y,\n z: this.camera.position.z,\n };\n }\n\n /**\n * Gets the camera's forward direction\n */\n getCameraDirection(): THREE.Vector3 {\n const direction = new THREE.Vector3();\n this.camera.getWorldDirection(direction);\n return direction;\n }\n\n /**\n * Dispose all resources\n */\n dispose(): void {\n window.removeEventListener('resize', this.resizeHandler);\n\n this.controls.dispose();\n this.renderer.dispose();\n\n // Remove renderer element\n if (this.renderer.domElement.parentNode) {\n this.renderer.domElement.parentNode.removeChild(this.renderer.domElement);\n }\n\n // Clear scene\n while (this.scene.children.length > 0) {\n const child = this.scene.children[0];\n this.scene.remove(child);\n }\n }\n}\n","import * as THREE from 'three';\nimport { SceneManager } from './SceneManager';\nimport { NodeFactory } from '../factory/NodeFactory';\nimport type {\n NodeData,\n InternalNode,\n NodeObject,\n Vector3Data,\n LODLevel\n} from '../utils/types';\nimport { validateNodeData } from '../utils/validation';\n\n/**\n * Node Manager\n * Handles node CRUD operations and position updates\n */\nexport class NodeManager {\n private sceneManager: SceneManager;\n private nodeFactory: NodeFactory;\n\n private nodes: Map<string, InternalNode> = new Map();\n private nodeObjects: Map<string, NodeObject> = new Map();\n\n constructor(sceneManager: SceneManager, nodeFactory: NodeFactory) {\n this.sceneManager = sceneManager;\n this.nodeFactory = nodeFactory;\n }\n\n /**\n * Checks if a node exists\n */\n hasNode(nodeId: string): boolean {\n return this.nodes.has(nodeId);\n }\n\n /**\n * Adds a node to the graph\n * @returns true if added, false if node already exists or invalid\n */\n addNode(nodeData: NodeData, lodLevel: LODLevel = 0): boolean {\n // Validate input\n if (!validateNodeData(nodeData)) {\n return false;\n }\n\n // Check for duplicate\n if (this.nodes.has(nodeData.id)) {\n console.warn(`[ForceGraph3D] Node with id \"${nodeData.id}\" already exists`);\n return false;\n }\n\n // Generate random position if not provided\n const position: Vector3Data = nodeData.position ?? {\n x: (Math.random() - 0.5) * 50,\n y: (Math.random() - 0.5) * 50,\n z: (Math.random() - 0.5) * 50,\n };\n\n // Create internal node with physics state\n const internalNode: InternalNode = {\n ...nodeData,\n position,\n velocity: { x: 0, y: 0, z: 0 },\n mass: 1,\n };\n\n // Create visual representation\n const nodeObject = this.nodeFactory.createNode(\n { ...nodeData, position },\n lodLevel\n );\n\n // Add to scene\n this.sceneManager.add(nodeObject.group);\n\n // Store references\n this.nodes.set(nodeData.id, internalNode);\n this.nodeObjects.set(nodeData.id, nodeObject);\n\n return true;\n }\n\n /**\n * Removes a node from the graph\n * @returns true if removed, false if not found\n */\n removeNode(nodeId: string): boolean {\n const node = this.nodes.get(nodeId);\n const nodeObject = this.nodeObjects.get(nodeId);\n\n if (!node || !nodeObject) {\n return false;\n }\n\n // Remove from scene\n this.sceneManager.remove(nodeObject.group);\n\n // Dispose resources\n this.nodeFactory.disposeNode(nodeObject);\n\n // Remove from maps\n this.nodes.delete(nodeId);\n this.nodeObjects.delete(nodeId);\n\n return true;\n }\n\n /**\n * Updates a node's properties\n */\n updateNode(nodeId: string, updates: Partial<NodeData>): boolean {\n const node = this.nodes.get(nodeId);\n const nodeObject = this.nodeObjects.get(nodeId);\n\n if (!node || !nodeObject) {\n console.warn(`[ForceGraph3D] Node \"${nodeId}\" not found`);\n return false;\n }\n\n // Update internal node data\n if (updates.label !== undefined) {\n node.label = updates.label;\n this.nodeFactory.updateNodeLabel(nodeObject, updates.label);\n }\n\n if (updates.color !== undefined) {\n node.color = updates.color;\n this.nodeFactory.updateNodeColor(nodeObject, updates.color);\n }\n\n // Store any additional custom data\n Object.keys(updates).forEach(key => {\n if (key !== 'id' && key !== 'label' && key !== 'color' && key !== 'position') {\n (node as Record<string, unknown>)[key] = updates[key as keyof NodeData];\n }\n });\n\n return true;\n }\n\n /**\n * Updates a node's position (called by physics engine)\n */\n updateNodePosition(nodeId: string, position: Vector3Data): void {\n const node = this.nodes.get(nodeId);\n const nodeObject = this.nodeObjects.get(nodeId);\n\n if (node && nodeObject) {\n node.position = position;\n nodeObject.group.position.set(position.x, position.y, position.z);\n }\n }\n\n /**\n * Updates a node's LOD level\n */\n updateNodeLOD(nodeId: string, lodLevel: LODLevel): void {\n const nodeObject = this.nodeObjects.get(nodeId);\n if (nodeObject) {\n this.nodeFactory.updateNodeLOD(nodeObject, lodLevel);\n }\n }\n\n /**\n * Gets a node by ID\n */\n getNode(nodeId: string): InternalNode | undefined {\n return this.nodes.get(nodeId);\n }\n\n /**\n * Gets a node's visual object\n */\n getNodeObject(nodeId: string): NodeObject | undefined {\n return this.nodeObjects.get(nodeId);\n }\n\n /**\n * Gets all nodes\n */\n getAllNodes(): Map<string, InternalNode> {\n return this.nodes;\n }\n\n /**\n * Gets all node objects (for raycasting)\n */\n getAllNodeObjects(): THREE.Object3D[] {\n const objects: THREE.Object3D[] = [];\n this.nodeObjects.forEach(nodeObject => {\n objects.push(nodeObject.group);\n });\n return objects;\n }\n\n /**\n * Gets all spheres (for raycasting)\n */\n getAllSpheres(): THREE.Mesh[] {\n const spheres: THREE.Mesh[] = [];\n this.nodeObjects.forEach(nodeObject => {\n spheres.push(nodeObject.sphere);\n });\n return spheres;\n }\n\n /**\n * Gets node count\n */\n getNodeCount(): number {\n return this.nodes.size;\n }\n\n /**\n * Clears all nodes\n */\n clear(): void {\n this.nodes.forEach((_, nodeId) => {\n this.removeNode(nodeId);\n });\n }\n\n /**\n * Dispose resources\n */\n dispose(): void {\n this.clear();\n }\n}\n","import * as THREE from 'three';\nimport { SceneManager } from './SceneManager';\nimport { NodeManager } from './NodeManager';\nimport { EdgeFactory } from '../factory/EdgeFactory';\nimport type { Edge, EdgeObject } from '../utils/types';\nimport { validateEdgeData, createEdgeKey } from '../utils/validation';\n\n/**\n * Edge Manager\n * Handles edge CRUD operations, position updates, and highlighting\n */\nexport class EdgeManager {\n private sceneManager: SceneManager;\n private nodeManager: NodeManager;\n private edgeFactory: EdgeFactory;\n\n private edges: Edge[] = [];\n private edgeObjects: EdgeObject[] = [];\n private edgeKeySet: Set<string> = new Set();\n private highlightedEdgeKey: string | null = null;\n\n constructor(\n sceneManager: SceneManager,\n nodeManager: NodeManager,\n edgeFactory: EdgeFactory\n ) {\n this.sceneManager = sceneManager;\n this.nodeManager = nodeManager;\n this.edgeFactory = edgeFactory;\n }\n\n /**\n * Checks if an edge exists\n */\n hasEdge(source: string, target: string): boolean {\n const key = createEdgeKey(source, target);\n return this.edgeKeySet.has(key);\n }\n\n /**\n * Adds an edge to the graph\n * @returns true if added, false if edge already exists or nodes don't exist\n */\n addEdge(edgeData: Edge): boolean {\n // Validate input\n if (!validateEdgeData(edgeData)) {\n return false;\n }\n\n // Check if source and target nodes exist\n if (!this.nodeManager.hasNode(edgeData.source)) {\n console.warn(`[ForceGraph3D] Source node \"${edgeData.source}\" does not exist`);\n return false;\n }\n\n if (!this.nodeManager.hasNode(edgeData.target)) {\n console.warn(`[ForceGraph3D] Target node \"${edgeData.target}\" does not exist`);\n return false;\n }\n\n // Check for duplicate edge (bidirectional check)\n const edgeKey = createEdgeKey(edgeData.source, edgeData.target);\n if (this.edgeKeySet.has(edgeKey)) {\n console.warn(`[ForceGraph3D] Edge \"${edgeData.source}\" -> \"${edgeData.target}\" already exists`);\n return false;\n }\n\n // Get node data\n const sourceNode = this.nodeManager.getNode(edgeData.source)!;\n const targetNode = this.nodeManager.getNode(edgeData.target)!;\n\n // Create visual representation with full node data\n const edgeObject = this.edgeFactory.createEdge(\n edgeData,\n sourceNode,\n targetNode,\n sourceNode.position,\n targetNode.position\n );\n\n // Add to scene\n this.sceneManager.add(edgeObject.line);\n\n // Store references\n this.edges.push(edgeData);\n this.edgeObjects.push(edgeObject);\n this.edgeKeySet.add(edgeKey);\n\n return true;\n }\n\n /**\n * Removes an edge from the graph\n * @returns true if removed, false if not found\n */\n removeEdge(source: string, target: string): boolean {\n const edgeKey = createEdgeKey(source, target);\n\n if (!this.edgeKeySet.has(edgeKey)) {\n return false;\n }\n\n // Find and remove the edge\n const index = this.edges.findIndex(e =>\n createEdgeKey(e.source, e.target) === edgeKey\n );\n\n if (index === -1) {\n return false;\n }\n\n const edgeObject = this.edgeObjects[index];\n\n // Remove from scene\n this.sceneManager.remove(edgeObject.line);\n\n // Dispose resources\n this.edgeFactory.disposeEdge(edgeObject);\n\n // Remove from arrays and set\n this.edges.splice(index, 1);\n this.edgeObjects.splice(index, 1);\n this.edgeKeySet.delete(edgeKey);\n\n // Clear highlight if this was the highlighted edge\n if (this.highlightedEdgeKey === edgeKey) {\n this.highlightedEdgeKey = null;\n }\n\n return true;\n }\n\n /**\n * Highlights an edge\n */\n highlightEdge(source: string, target: string): void {\n const edgeKey = createEdgeKey(source, target);\n\n // Unhighlight previous edge if different\n if (this.highlightedEdgeKey && this.highlightedEdgeKey !== edgeKey) {\n this.unhighlightCurrentEdge();\n }\n\n // Find and highlight the edge\n const index = this.edges.findIndex(e =>\n createEdgeKey(e.source, e.target) === edgeKey\n );\n\n if (index !== -1) {\n this.edgeFactory.highlightEdge(this.edgeObjects[index]);\n this.highlightedEdgeKey = edgeKey;\n }\n }\n\n /**\n * Unhighlights the currently highlighted edge\n */\n unhighlightCurrentEdge(): void {\n if (!this.highlightedEdgeKey) return;\n\n const index = this.edges.findIndex(e =>\n createEdgeKey(e.source, e.target) === this.highlightedEdgeKey\n );\n\n if (index !== -1) {\n this.edgeFactory.unhighlightEdge(this.edgeObjects[index]);\n }\n\n this.highlightedEdgeKey = null;\n }\n\n /**\n * Removes all edges connected to a node\n */\n removeEdgesForNode(nodeId: string): void {\n // Find all edges connected to this node\n const edgesToRemove: Array<{ source: string; target: string }> = [];\n\n this.edges.forEach(edge => {\n if (edge.source === nodeId || edge.target === nodeId) {\n edgesToRemove.push({ source: edge.source, target: edge.target });\n }\n });\n\n // Remove each edge\n edgesToRemove.forEach(edge => {\n this.removeEdge(edge.source, edge.target);\n });\n }\n\n /**\n * Gets all edges for a node\n */\n getEdgesForNode(nodeId: string): Edge[] {\n return this.edges.filter(e => e.source === nodeId || e.target === nodeId);\n }\n\n /**\n * Gets neighbor node IDs for a node\n */\n getNeighborIds(nodeId: string): string[] {\n const neighbors: string[] = [];\n\n this.edges.forEach(edge => {\n if (edge.source === nodeId) {\n neighbors.push(edge.target);\n } else if (edge.target === nodeId) {\n neighbors.push(edge.source);\n }\n });\n\n return [...new Set(neighbors)]; // Remove duplicates\n }\n\n /**\n * Updates all edge positions based on current node positions\n */\n updateEdgePositions(): void {\n this.edgeObjects.forEach((edgeObject, index) => {\n const edge = this.edges[index];\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n\n if (sourceNode && targetNode) {\n this.edgeFactory.updateEdgePositions(\n edgeObject,\n sourceNode.position,\n targetNode.position\n );\n }\n });\n }\n\n /**\n * Gets all edges\n */\n getAllEdges(): Edge[] {\n return this.edges;\n }\n\n /**\n * Gets all edge line objects (for raycasting)\n */\n getAllEdgeLines(): THREE.Line[] {\n return this.edgeObjects.map(eo => eo.line);\n }\n\n /**\n * Gets edge count\n */\n getEdgeCount(): number {\n return this.edges.length;\n }\n\n /**\n * Clears all edges\n */\n clear(): void {\n // Remove all edges from scene and dispose\n this.edgeObjects.forEach(edgeObject => {\n this.sceneManager.remove(edgeObject.line);\n this.edgeFactory.disposeEdge(edgeObject);\n });\n\n this.edges = [];\n this.edgeObjects = [];\n this.edgeKeySet.clear();\n this.highlightedEdgeKey = null;\n }\n\n /**\n * Dispose resources\n */\n dispose(): void {\n this.clear();\n }\n}\n","import type { InternalNode, Edge, Vector3Data } from '../utils/types';\n\n/**\n * Graph Engine\n * Force-directed physics simulation with Barnes-Hut optimization\n */\nexport class GraphEngine {\n private nodes: Map<string, InternalNode>;\n private edges: Edge[];\n\n // Physics parameters\n private repulsionStrength: number;\n private attractionStrength: number;\n private damping: number;\n private useBarnesHut: boolean;\n private barnesHutTheta: number;\n\n // Simulation state\n private alpha: number = 1;\n private alphaDecay: number = 0.0228;\n private alphaMin: number = 0.001;\n private alphaTarget: number = 0;\n\n constructor(\n nodes: Map<string, InternalNode>,\n edges: Edge[],\n options: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n useBarnesHut?: boolean;\n barnesHutTheta?: number;\n } = {}\n ) {\n this.nodes = nodes;\n this.edges = edges;\n\n this.repulsionStrength = options.repulsionStrength ?? 100;\n this.attractionStrength = options.attractionStrength ?? 0.01;\n this.damping = options.damping ?? 0.9;\n this.useBarnesHut = options.useBarnesHut ?? false;\n this.barnesHutTheta = options.barnesHutTheta ?? 0.5;\n }\n\n /**\n * Runs one simulation step\n */\n simulate(): void {\n if (this.alpha < this.alphaMin) return;\n\n const nodeCount = this.nodes.size;\n\n // Auto-enable Barnes-Hut for large graphs\n const shouldUseBarnesHut = this.useBarnesHut || nodeCount >= 1000;\n\n // Calculate repulsion forces\n if (shouldUseBarnesHut && nodeCount >= 100) {\n this.calculateRepulsionBarnesHut();\n } else {\n this.calculateRepulsionBruteForce();\n }\n\n // Calculate attraction forces along edges\n this.calculateAttraction();\n\n // Apply velocities and damping\n this.applyForces();\n\n // Decay alpha\n this.alpha += (this.alphaTarget - this.alpha) * this.alphaDecay;\n }\n\n /**\n * Brute force repulsion - O(n²)\n */\n private calculateRepulsionBruteForce(): void {\n const nodesArray = Array.from(this.nodes.values());\n const n = nodesArray.length;\n\n for (let i = 0; i < n; i++) {\n const nodeA = nodesArray[i];\n\n for (let j = i + 1; j < n; j++) {\n const nodeB = nodesArray[j];\n\n const dx = nodeB.position.x - nodeA.position.x;\n const dy = nodeB.position.y - nodeA.position.y;\n const dz = nodeB.position.z - nodeA.position.z;\n\n let distSq = dx * dx + dy * dy + dz * dz;\n if (distSq < 0.01) distSq = 0.01; // Prevent division by zero\n\n const dist = Math.sqrt(distSq);\n const force = (this.repulsionStrength * this.alpha) / distSq;\n\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n const fz = (dz / dist) * force;\n\n // Apply equal and opposite forces\n nodeA.velocity.x -= fx / nodeA.mass;\n nodeA.velocity.y -= fy / nodeA.mass;\n nodeA.velocity.z -= fz / nodeA.mass;\n\n nodeB.velocity.x += fx / nodeB.mass;\n nodeB.velocity.y += fy / nodeB.mass;\n nodeB.velocity.z += fz / nodeB.mass;\n }\n }\n }\n\n /**\n * Barnes-Hut approximation - O(n log n)\n */\n private calculateRepulsionBarnesHut(): void {\n const nodesArray = Array.from(this.nodes.values());\n\n // Build octree\n const octree = new Octree(nodesArray);\n\n // Calculate forces using octree\n for (const node of nodesArray) {\n this.calculateForceFromOctree(node, octree.root);\n }\n }\n\n /**\n * Recursive force calculation using octree\n */\n private calculateForceFromOctree(node: InternalNode, octreeNode: OctreeNode): void {\n if (octreeNode.isLeaf) {\n if (octreeNode.node && octreeNode.node.id !== node.id) {\n this.applyRepulsionBetween(node, octreeNode.node);\n }\n return;\n }\n\n if (octreeNode.mass === 0) return;\n\n const dx = octreeNode.centerOfMass.x - node.position.x;\n const dy = octreeNode.centerOfMass.y - node.position.y;\n const dz = octreeNode.centerOfMass.z - node.position.z;\n const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n // Check if we can use the approximation\n if (octreeNode.size / dist < this.barnesHutTheta) {\n // Treat as single body\n const distSq = Math.max(dist * dist, 0.01);\n const force = (this.repulsionStrength * this.alpha * octreeNode.mass) / distSq;\n\n node.velocity.x -= (dx / dist) * force / node.mass;\n node.velocity.y -= (dy / dist) * force / node.mass;\n node.velocity.z -= (dz / dist) * force / node.mass;\n } else {\n // Recurse into children\n for (const child of octreeNode.children) {\n if (child) {\n this.calculateForceFromOctree(node, child);\n }\n }\n }\n }\n\n /**\n * Apply repulsion between two nodes\n */\n private applyRepulsionBetween(nodeA: InternalNode, nodeB: InternalNode): void {\n const dx = nodeB.position.x - nodeA.position.x;\n const dy = nodeB.position.y - nodeA.position.y;\n const dz = nodeB.position.z - nodeA.position.z;\n\n let distSq = dx * dx + dy * dy + dz * dz;\n if (distSq < 0.01) distSq = 0.01;\n\n const dist = Math.sqrt(distSq);\n const force = (this.repulsionStrength * this.alpha) / distSq;\n\n nodeA.velocity.x -= (dx / dist) * force / nodeA.mass;\n nodeA.velocity.y -= (dy / dist) * force / nodeA.mass;\n nodeA.velocity.z -= (dz / dist) * force / nodeA.mass;\n }\n\n /**\n * Calculate attraction forces along edges\n */\n private calculateAttraction(): void {\n for (const edge of this.edges) {\n const sourceNode = this.nodes.get(edge.source);\n const targetNode = this.nodes.get(edge.target);\n\n if (!sourceNode || !targetNode) continue;\n\n const dx = targetNode.position.x - sourceNode.position.x;\n const dy = targetNode.position.y - sourceNode.position.y;\n const dz = targetNode.position.z - sourceNode.position.z;\n\n const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);\n if (dist < 0.01) continue;\n\n // Spring-like attraction (Hooke's law)\n const targetDist = 15; // Ideal edge length\n const force = (dist - targetDist) * this.attractionStrength * this.alpha;\n\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n const fz = (dz / dist) * force;\n\n sourceNode.velocity.x += fx / sourceNode.mass;\n sourceNode.velocity.y += fy / sourceNode.mass;\n sourceNode.velocity.z += fz / sourceNode.mass;\n\n targetNode.velocity.x -= fx / targetNode.mass;\n targetNode.velocity.y -= fy / targetNode.mass;\n targetNode.velocity.z -= fz / targetNode.mass;\n }\n }\n\n /**\n * Apply velocities and damping to positions\n */\n private applyForces(): void {\n for (const node of this.nodes.values()) {\n // Apply damping\n node.velocity.x *= this.damping;\n node.velocity.y *= this.damping;\n node.velocity.z *= this.damping;\n\n // Update position\n node.position.x += node.velocity.x;\n node.position.y += node.velocity.y;\n node.position.z += node.velocity.z;\n }\n }\n\n /**\n * Updates the edges reference\n */\n setEdges(edges: Edge[]): void {\n this.edges = edges;\n }\n\n /**\n * Resets the simulation (restarts with full energy)\n */\n restart(): void {\n this.alpha = 1;\n }\n\n /**\n * Gets the current alpha value\n */\n getAlpha(): number {\n return this.alpha;\n }\n\n /**\n * Sets physics parameters\n */\n setPhysicsParams(params: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n }): void {\n if (params.repulsionStrength !== undefined) {\n this.repulsionStrength = params.repulsionStrength;\n }\n if (params.attractionStrength !== undefined) {\n this.attractionStrength = params.attractionStrength;\n }\n if (params.damping !== undefined) {\n this.damping = params.damping;\n }\n }\n}\n\n// ============================================================================\n// Octree Implementation for Barnes-Hut\n// ============================================================================\n\ninterface OctreeNode {\n bounds: { min: Vector3Data; max: Vector3Data };\n size: number;\n centerOfMass: Vector3Data;\n mass: number;\n isLeaf: boolean;\n node: InternalNode | null;\n children: (OctreeNode | null)[];\n}\n\nclass Octree {\n root: OctreeNode;\n\n constructor(nodes: InternalNode[]) {\n // Calculate bounding box\n const bounds = this.calculateBounds(nodes);\n this.root = this.buildTree(nodes, bounds);\n }\n\n private calculateBounds(nodes: InternalNode[]): { min: Vector3Data; max: Vector3Data } {\n if (nodes.length === 0) {\n return {\n min: { x: -100, y: -100, z: -100 },\n max: { x: 100, y: 100, z: 100 },\n };\n }\n\n const min = { x: Infinity, y: Infinity, z: Infinity };\n const max = { x: -Infinity, y: -Infinity, z: -Infinity };\n\n for (const node of nodes) {\n min.x = Math.min(min.x, node.position.x);\n min.y = Math.min(min.y, node.position.y);\n min.z = Math.min(min.z, node.position.z);\n max.x = Math.max(max.x, node.position.x);\n max.y = Math.max(max.y, node.position.y);\n max.z = Math.max(max.z, node.position.z);\n }\n\n // Add padding\n const padding = 10;\n min.x -= padding; min.y -= padding; min.z -= padding;\n max.x += padding; max.y += padding; max.z += padding;\n\n return { min, max };\n }\n\n private buildTree(\n nodes: InternalNode[],\n bounds: { min: Vector3Data; max: Vector3Data },\n depth: number = 0\n ): OctreeNode {\n const size = Math.max(\n bounds.max.x - bounds.min.x,\n bounds.max.y - bounds.min.y,\n bounds.max.z - bounds.min.z\n );\n\n // Base case: empty or single node\n if (nodes.length === 0) {\n return {\n bounds,\n size,\n centerOfMass: { x: 0, y: 0, z: 0 },\n mass: 0,\n isLeaf: true,\n node: null,\n children: [],\n };\n }\n\n if (nodes.length === 1 || depth > 20) {\n // Calculate center of mass\n let totalMass = 0;\n const com = { x: 0, y: 0, z: 0 };\n\n for (const node of nodes) {\n totalMass += node.mass;\n com.x += node.position.x * node.mass;\n com.y += node.position.y * node.mass;\n com.z += node.position.z * node.mass;\n }\n\n if (totalMass > 0) {\n com.x /= totalMass;\n com.y /= totalMass;\n com.z /= totalMass;\n }\n\n return {\n bounds,\n size,\n centerOfMass: com,\n mass: totalMass,\n isLeaf: true,\n node: nodes[0],\n children: [],\n };\n }\n\n // Divide into 8 octants\n const midX = (bounds.min.x + bounds.max.x) / 2;\n const midY = (bounds.min.y + bounds.max.y) / 2;\n const midZ = (bounds.min.z + bounds.max.z) / 2;\n\n const octants: InternalNode[][] = [[], [], [], [], [], [], [], []];\n\n for (const node of nodes) {\n const idx =\n (node.position.x >= midX ? 1 : 0) +\n (node.position.y >= midY ? 2 : 0) +\n (node.position.z >= midZ ? 4 : 0);\n octants[idx].push(node);\n }\n\n const childBounds: Array<{ min: Vector3Data; max: Vector3Data }> = [\n { min: { x: bounds.min.x, y: bounds.min.y, z: bounds.min.z }, max: { x: midX, y: midY, z: midZ } },\n { min: { x: midX, y: bounds.min.y, z: bounds.min.z }, max: { x: bounds.max.x, y: midY, z: midZ } },\n { min: { x: bounds.min.x, y: midY, z: bounds.min.z }, max: { x: midX, y: bounds.max.y, z: midZ } },\n { min: { x: midX, y: midY, z: bounds.min.z }, max: { x: bounds.max.x, y: bounds.max.y, z: midZ } },\n { min: { x: bounds.min.x, y: bounds.min.y, z: midZ }, max: { x: midX, y: midY, z: bounds.max.z } },\n { min: { x: midX, y: bounds.min.y, z: midZ }, max: { x: bounds.max.x, y: midY, z: bounds.max.z } },\n { min: { x: bounds.min.x, y: midY, z: midZ }, max: { x: midX, y: bounds.max.y, z: bounds.max.z } },\n { min: { x: midX, y: midY, z: midZ }, max: { x: bounds.max.x, y: bounds.max.y, z: bounds.max.z } },\n ];\n\n const children: (OctreeNode | null)[] = [];\n let totalMass = 0;\n const com = { x: 0, y: 0, z: 0 };\n\n for (let i = 0; i < 8; i++) {\n if (octants[i].length > 0) {\n const child = this.buildTree(octants[i], childBounds[i], depth + 1);\n children.push(child);\n\n totalMass += child.mass;\n com.x += child.centerOfMass.x * child.mass;\n com.y += child.centerOfMass.y * child.mass;\n com.z += child.centerOfMass.z * child.mass;\n } else {\n children.push(null);\n }\n }\n\n if (totalMass > 0) {\n com.x /= totalMass;\n com.y /= totalMass;\n com.z /= totalMass;\n }\n\n return {\n bounds,\n size,\n centerOfMass: com,\n mass: totalMass,\n isLeaf: false,\n node: null,\n children,\n };\n }\n}\n","import { SceneManager } from './SceneManager';\n\n/**\n * Renderer Manager\n * Handles animation loop with frame rate control\n */\nexport class RendererManager {\n private sceneManager: SceneManager;\n private animationId: number | null = null;\n private isRunning: boolean = false;\n\n private frameInterval: number;\n private lastFrameTime: number = 0;\n\n private onSimulate: () => void;\n private onRender: () => void;\n\n // Performance monitoring\n private frameCount: number = 0;\n private fpsStartTime: number = 0;\n private currentFPS: number = 60;\n\n constructor(\n sceneManager: SceneManager,\n onSimulate: () => void,\n onRender: () => void,\n targetFPS: number = 60\n ) {\n this.sceneManager = sceneManager;\n this.onSimulate = onSimulate;\n this.onRender = onRender;\n this.frameInterval = 1000 / targetFPS;\n }\n\n /**\n * Starts the animation loop\n */\n start(): void {\n if (this.isRunning) return;\n\n this.isRunning = true;\n this.lastFrameTime = performance.now();\n this.fpsStartTime = performance.now();\n this.frameCount = 0;\n\n this.animate();\n }\n\n /**\n * Stops the animation loop\n */\n stop(): void {\n this.isRunning = false;\n if (this.animationId !== null) {\n cancelAnimationFrame(this.animationId);\n this.animationId = null;\n }\n }\n\n /**\n * Main animation loop\n */\n private animate = (): void => {\n if (!this.isRunning) return;\n\n this.animationId = requestAnimationFrame(this.animate);\n\n const currentTime = performance.now();\n const elapsed = currentTime - this.lastFrameTime;\n\n // Frame rate limiting\n if (elapsed < this.frameInterval) {\n return;\n }\n\n // Update timing\n this.lastFrameTime = currentTime - (elapsed % this.frameInterval);\n\n // Update FPS counter\n this.frameCount++;\n const fpsElapsed = currentTime - this.fpsStartTime;\n if (fpsElapsed >= 1000) {\n this.currentFPS = this.frameCount / (fpsElapsed / 1000);\n this.frameCount = 0;\n this.fpsStartTime = currentTime;\n }\n\n // Run physics simulation\n this.onSimulate();\n\n // Call additional render callbacks\n this.onRender();\n\n // Render scene\n this.sceneManager.render();\n };\n\n /**\n * Gets the current FPS\n */\n getFPS(): number {\n return Math.round(this.currentFPS);\n }\n\n /**\n * Sets target FPS\n */\n setTargetFPS(fps: number): void {\n this.frameInterval = 1000 / fps;\n }\n\n /**\n * Checks if animation is running\n */\n isAnimating(): boolean {\n return this.isRunning;\n }\n\n /**\n * Dispose\n */\n dispose(): void {\n this.stop();\n }\n}\n","import * as THREE from 'three';\n\n/**\n * Material Factory\n * Creates gradient glass materials with radial transparency\n */\nexport class MaterialFactory {\n private envMap: THREE.CubeTexture | null = null;\n private materialCache: Map<string, THREE.ShaderMaterial> = new Map();\n\n // Color palette - white and tangerine\n private readonly COLORS = [\n 0xffffff, // White\n 0xff9966, // Tangerine/orange\n 0xffcc99, // Light peach\n 0xffeedd, // Cream\n 0xff8844, // Darker tangerine\n ];\n\n constructor() {\n this.createEnvironmentMap();\n }\n\n /**\n * Creates environment map for glass reflections on dark background\n */\n private createEnvironmentMap(): void {\n const size = 256;\n\n // Create gradient backgrounds for each face - dark theme\n const faces: HTMLCanvasElement[] = [];\n const faceConfigs = [\n // Subtle colored gradients for interesting reflections\n { colors: ['#1a1a2e', '#16213e', '#0f3460'] }, // +x\n { colors: ['#2d1f1f', '#1a1a1a', '#0f0f0f'] }, // -x\n { colors: ['#1f2d2d', '#1a1a2e', '#101020'] }, // +y\n { colors: ['#0a0a0a', '#050505', '#000000'] }, // -y\n { colors: ['#1a1a2e', '#0f1a2a', '#0a0a15'] }, // +z\n { colors: ['#2d1a1a', '#1a0a0a', '#0f0505'] }, // -z\n ];\n\n for (const config of faceConfigs) {\n const faceCanvas = document.createElement('canvas');\n faceCanvas.width = size;\n faceCanvas.height = size;\n const faceCtx = faceCanvas.getContext('2d')!;\n\n const gradient = faceCtx.createRadialGradient(\n size / 2, size / 2, 0,\n size / 2, size / 2, size * 0.8\n );\n gradient.addColorStop(0, config.colors[0]);\n gradient.addColorStop(0.5, config.colors[1]);\n gradient.addColorStop(1, config.colors[2]);\n\n faceCtx.fillStyle = gradient;\n faceCtx.fillRect(0, 0, size, size);\n\n // Add subtle noise\n const imageData = faceCtx.getImageData(0, 0, size, size);\n for (let i = 0; i < imageData.data.length; i += 4) {\n const noise = (Math.random() - 0.5) * 5;\n imageData.data[i] = Math.min(255, Math.max(0, imageData.data[i] + noise));\n imageData.data[i + 1] = Math.min(255, Math.max(0, imageData.data[i + 1] + noise));\n imageData.data[i + 2] = Math.min(255, Math.max(0, imageData.data[i + 2] + noise));\n }\n faceCtx.putImageData(imageData, 0, 0);\n\n faces.push(faceCanvas);\n }\n\n this.envMap = new THREE.CubeTexture(faces.map(c => {\n const img = new Image();\n img.src = c.toDataURL();\n return img;\n }));\n this.envMap.needsUpdate = true;\n }\n\n /**\n * Gets a random color from the palette\n */\n getRandomColor(): number {\n return this.COLORS[Math.floor(Math.random() * this.COLORS.length)];\n }\n\n /**\n * Creates a gradient glass material with white glow in center\n * All balls use the same tangerine color with white center glow\n */\n createGlassMaterial(_color?: number): THREE.ShaderMaterial {\n // Single consistent color - tangerine\n const color = 0xff9966;\n const cacheKey = 'glass-single';\n\n if (this.materialCache.has(cacheKey)) {\n return this.materialCache.get(cacheKey)!.clone();\n }\n\n const threeColor = new THREE.Color(color);\n\n // Custom shader for radial white glow effect\n const material = new THREE.ShaderMaterial({\n uniforms: {\n uColor: { value: threeColor },\n uEnvMap: { value: this.envMap },\n uGlowColor: { value: new THREE.Color(0xffffff) },\n uGlowIntensity: { value: 0.8 },\n uReflectivity: { value: 0.4 },\n uFresnelPower: { value: 2.5 },\n },\n vertexShader: `\n varying vec3 vNormal;\n varying vec3 vViewPosition;\n varying vec3 vWorldPosition;\n varying vec2 vUv;\n \n void main() {\n vNormal = normalize(normalMatrix * normal);\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = -mvPosition.xyz;\n vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;\n vUv = uv;\n gl_Position = projectionMatrix * mvPosition;\n }\n `,\n fragmentShader: `\n uniform vec3 uColor;\n uniform vec3 uGlowColor;\n uniform samplerCube uEnvMap;\n uniform float uGlowIntensity;\n uniform float uReflectivity;\n uniform float uFresnelPower;\n \n varying vec3 vNormal;\n varying vec3 vViewPosition;\n varying vec3 vWorldPosition;\n varying vec2 vUv;\n \n void main() {\n vec3 viewDir = normalize(vViewPosition);\n vec3 normal = normalize(vNormal);\n \n // Fresnel effect - edges are more visible\n float fresnel = pow(1.0 - abs(dot(viewDir, normal)), uFresnelPower);\n \n // Center glow: bright white in center, fading to base color at edges\n // Center is where normal faces camera directly (low fresnel)\n float centerGlow = (1.0 - fresnel) * uGlowIntensity;\n \n // Environment reflection on edges\n vec3 reflectDir = reflect(-viewDir, normal);\n vec3 envColor = textureCube(uEnvMap, reflectDir).rgb;\n \n // Base color with reflection at edges\n vec3 baseColor = uColor;\n vec3 edgeColor = mix(baseColor, envColor, uReflectivity * fresnel);\n \n // Blend: white glow in center, colored edges\n vec3 finalColor = mix(edgeColor, uGlowColor, centerGlow);\n \n // Add rim highlight for glass effect\n float rimLight = pow(fresnel, 4.0) * 0.4;\n finalColor += vec3(rimLight) * uColor;\n \n // Opacity: fully opaque with glow effect visible\n float opacity = 0.85 + fresnel * 0.15;\n \n gl_FragColor = vec4(finalColor, opacity);\n }\n `,\n transparent: true,\n side: THREE.FrontSide,\n depthWrite: true,\n blending: THREE.NormalBlending,\n });\n\n this.materialCache.set(cacheKey, material);\n return material.clone();\n }\n\n /**\n * Creates material for edges (light color for dark background)\n */\n createEdgeMaterial(color: number = 0x666666, opacity: number = 0.4): THREE.LineBasicMaterial {\n return new THREE.LineBasicMaterial({\n color: color,\n transparent: true,\n opacity: opacity,\n linewidth: 1,\n });\n }\n\n /**\n * Creates highlighted edge material\n */\n createHighlightedEdgeMaterial(): THREE.LineBasicMaterial {\n return new THREE.LineBasicMaterial({\n color: 0xff9966, // Tangerine highlight\n transparent: false,\n opacity: 1.0,\n linewidth: 2,\n });\n }\n\n /**\n * Creates a sprite material for labels (light text for dark background)\n */\n createLabelMaterial(text: string, fontSize: number = 24): THREE.SpriteMaterial {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d')!;\n\n // Set canvas size based on text length\n ctx.font = `600 ${fontSize}px Inter, -apple-system, sans-serif`;\n const metrics = ctx.measureText(text);\n const textWidth = metrics.width;\n\n canvas.width = Math.max(128, textWidth + 24);\n canvas.height = fontSize + 20;\n\n // Clear and draw text\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.font = `600 ${fontSize}px Inter, -apple-system, sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Light text with dark shadow for dark background\n ctx.shadowColor = 'rgba(0, 0, 0, 0.8)';\n ctx.shadowBlur = 4;\n ctx.shadowOffsetX = 1;\n ctx.shadowOffsetY = 1;\n\n ctx.fillStyle = 'rgba(255, 255, 255, 0.95)';\n ctx.fillText(text, canvas.width / 2, canvas.height / 2);\n\n const texture = new THREE.CanvasTexture(canvas);\n texture.needsUpdate = true;\n\n return new THREE.SpriteMaterial({\n map: texture,\n transparent: true,\n depthTest: false,\n depthWrite: false,\n });\n }\n\n /**\n * Gets environment map\n */\n getEnvMap(): THREE.CubeTexture | null {\n return this.envMap;\n }\n\n /**\n * Dispose all cached materials\n */\n dispose(): void {\n this.materialCache.forEach(material => material.dispose());\n this.materialCache.clear();\n if (this.envMap) {\n this.envMap.dispose();\n }\n }\n}\n","import * as THREE from 'three';\nimport { MaterialFactory } from './MaterialFactory';\nimport type { NodeData, LODLevel, NodeObject } from '../utils/types';\n\n/**\n * Node Factory\n * Creates glass ball nodes with labels\n */\nexport class NodeFactory {\n private materialFactory: MaterialFactory;\n private geometryCache: Map<string, THREE.SphereGeometry> = new Map();\n private nodeRadius: number;\n private lodSegments: number[];\n private defaultNodeColor: number;\n\n constructor(\n materialFactory: MaterialFactory,\n nodeRadius: number = 2,\n lodSegments: number[] = [32, 16, 8],\n defaultNodeColor: number = 0xff9966\n ) {\n this.materialFactory = materialFactory;\n this.nodeRadius = nodeRadius;\n this.lodSegments = lodSegments;\n this.defaultNodeColor = defaultNodeColor;\n this.initGeometryCache();\n }\n\n /**\n * Pre-create geometries for each LOD level\n */\n private initGeometryCache(): void {\n this.lodSegments.forEach((segments, index) => {\n const key = `lod-${index}`;\n this.geometryCache.set(\n key,\n new THREE.SphereGeometry(this.nodeRadius, segments, segments)\n );\n });\n }\n\n /**\n * Gets geometry for the specified LOD level\n */\n private getGeometry(lodLevel: LODLevel): THREE.SphereGeometry {\n const key = `lod-${lodLevel}`;\n if (this.geometryCache.has(key)) {\n return this.geometryCache.get(key)!;\n }\n // Fallback to highest detail\n return this.geometryCache.get('lod-0')!;\n }\n\n /**\n * Creates a node visual (glass ball + label)\n */\n createNode(nodeData: NodeData, lodLevel: LODLevel = 0): NodeObject {\n const group = new THREE.Group();\n group.name = `node-${nodeData.id}`;\n group.userData = { nodeId: nodeData.id, nodeData };\n\n // Create glass sphere\n const geometry = this.getGeometry(lodLevel);\n const material = this.materialFactory.createGlassMaterial(\n nodeData.color ?? this.defaultNodeColor\n );\n const sphere = new THREE.Mesh(geometry, material);\n sphere.castShadow = true;\n sphere.receiveShadow = true;\n group.add(sphere);\n\n // Create label sprite\n const labelMaterial = this.materialFactory.createLabelMaterial(nodeData.label);\n const label = new THREE.Sprite(labelMaterial);\n\n // Position label above the sphere\n label.position.y = this.nodeRadius + 1.5;\n label.scale.set(4, 1, 1);\n group.add(label);\n\n // Set initial position\n if (nodeData.position) {\n group.position.set(\n nodeData.position.x,\n nodeData.position.y,\n nodeData.position.z\n );\n }\n\n return {\n group,\n sphere,\n label,\n lodLevel,\n };\n }\n\n /**\n * Updates the LOD level of a node\n */\n updateNodeLOD(nodeObject: NodeObject, newLodLevel: LODLevel): void {\n if (nodeObject.lodLevel === newLodLevel) return;\n\n // Get new geometry\n const newGeometry = this.getGeometry(newLodLevel);\n\n // Update the sphere's geometry\n nodeObject.sphere.geometry = newGeometry;\n nodeObject.lodLevel = newLodLevel;\n }\n\n /**\n * Updates the color of a node\n */\n updateNodeColor(nodeObject: NodeObject, color: number): void {\n // Dispose old material and create new one\n if (nodeObject.sphere.material instanceof THREE.Material) {\n nodeObject.sphere.material.dispose();\n }\n nodeObject.sphere.material = this.materialFactory.createGlassMaterial(color);\n }\n\n /**\n * Updates the label of a node\n */\n updateNodeLabel(nodeObject: NodeObject, label: string): void {\n // Dispose old sprite material\n if (nodeObject.label.material instanceof THREE.SpriteMaterial) {\n if (nodeObject.label.material.map) {\n nodeObject.label.material.map.dispose();\n }\n nodeObject.label.material.dispose();\n }\n\n // Create new label material\n nodeObject.label.material = this.materialFactory.createLabelMaterial(label);\n }\n\n /**\n * Disposes a node's resources\n */\n disposeNode(nodeObject: NodeObject): void {\n // Dispose sphere material\n if (nodeObject.sphere.material instanceof THREE.Material) {\n nodeObject.sphere.material.dispose();\n }\n\n // Dispose label\n if (nodeObject.label.material instanceof THREE.SpriteMaterial) {\n if (nodeObject.label.material.map) {\n nodeObject.label.material.map.dispose();\n }\n nodeObject.label.material.dispose();\n }\n }\n\n /**\n * Dispose factory resources\n */\n dispose(): void {\n this.geometryCache.forEach(geometry => geometry.dispose());\n this.geometryCache.clear();\n }\n}\n","import * as THREE from 'three';\nimport { MaterialFactory } from './MaterialFactory';\nimport type { EdgeObject, Vector3Data, Edge, NodeData } from '../utils/types';\n\n/**\n * Edge Factory\n * Creates edge lines between nodes with hover highlighting support\n */\nexport class EdgeFactory {\n private materialFactory: MaterialFactory;\n private edgeColor: number;\n private edgeOpacity: number;\n private defaultMaterial: THREE.LineBasicMaterial | null = null;\n private highlightMaterial: THREE.LineBasicMaterial | null = null;\n\n constructor(\n materialFactory: MaterialFactory,\n edgeColor: number = 0x999999,\n edgeOpacity: number = 0.5\n ) {\n this.materialFactory = materialFactory;\n this.edgeColor = edgeColor;\n this.edgeOpacity = edgeOpacity;\n }\n\n /**\n * Gets or creates the default edge material\n */\n private getDefaultMaterial(): THREE.LineBasicMaterial {\n if (!this.defaultMaterial) {\n this.defaultMaterial = this.materialFactory.createEdgeMaterial(\n this.edgeColor,\n this.edgeOpacity\n );\n }\n return this.defaultMaterial;\n }\n\n /**\n * Gets or creates the highlight material\n */\n private getHighlightMaterial(): THREE.LineBasicMaterial {\n if (!this.highlightMaterial) {\n this.highlightMaterial = this.materialFactory.createHighlightedEdgeMaterial();\n }\n return this.highlightMaterial;\n }\n\n /**\n * Creates an edge line between two positions\n */\n createEdge(\n edge: Edge,\n sourceNode: NodeData,\n targetNode: NodeData,\n sourcePos: Vector3Data,\n targetPos: Vector3Data\n ): EdgeObject {\n const geometry = new THREE.BufferGeometry();\n\n // Set initial positions\n const positions = new Float32Array([\n sourcePos.x, sourcePos.y, sourcePos.z,\n targetPos.x, targetPos.y, targetPos.z,\n ]);\n geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));\n\n const material = this.getDefaultMaterial().clone();\n\n const line = new THREE.Line(geometry, material);\n line.name = `edge-${edge.source}-${edge.target}`;\n\n // Store full edge and node data for hover detection\n line.userData = {\n source: edge.source,\n target: edge.target,\n edge: edge,\n sourceNode: sourceNode,\n targetNode: targetNode,\n };\n line.frustumCulled = true;\n\n return {\n line,\n source: edge.source,\n target: edge.target,\n };\n }\n\n /**\n * Highlights an edge\n */\n highlightEdge(edgeObject: EdgeObject): void {\n if (edgeObject.line.material instanceof THREE.Material) {\n edgeObject.line.material.dispose();\n }\n edgeObject.line.material = this.getHighlightMaterial().clone();\n }\n\n /**\n * Resets an edge to default appearance\n */\n unhighlightEdge(edgeObject: EdgeObject): void {\n if (edgeObject.line.material instanceof THREE.Material) {\n edgeObject.line.material.dispose();\n }\n edgeObject.line.material = this.getDefaultMaterial().clone();\n }\n\n /**\n * Updates an edge's positions\n */\n updateEdgePositions(\n edgeObject: EdgeObject,\n sourcePos: Vector3Data,\n targetPos: Vector3Data\n ): void {\n const positions = edgeObject.line.geometry.attributes.position;\n const posArray = positions.array as Float32Array;\n\n posArray[0] = sourcePos.x;\n posArray[1] = sourcePos.y;\n posArray[2] = sourcePos.z;\n posArray[3] = targetPos.x;\n posArray[4] = targetPos.y;\n posArray[5] = targetPos.z;\n\n positions.needsUpdate = true;\n edgeObject.line.geometry.computeBoundingSphere();\n }\n\n /**\n * Disposes an edge's resources\n */\n disposeEdge(edgeObject: EdgeObject): void {\n edgeObject.line.geometry.dispose();\n if (edgeObject.line.material instanceof THREE.Material) {\n edgeObject.line.material.dispose();\n }\n }\n\n /**\n * Dispose factory resources\n */\n dispose(): void {\n if (this.defaultMaterial) {\n this.defaultMaterial.dispose();\n }\n if (this.highlightMaterial) {\n this.highlightMaterial.dispose();\n }\n }\n}\n","import * as THREE from 'three';\nimport type { LODLevel, Vector3Data } from '../utils/types';\nimport { LODLevel as LODLevelEnum } from '../utils/types';\n\n/**\n * LOD Manager\n * Manages Level of Detail for nodes based on distance from camera\n */\nexport class LODManager {\n private camera: THREE.PerspectiveCamera;\n private lodDistances: number[];\n private enabled: boolean;\n\n constructor(\n camera: THREE.PerspectiveCamera,\n lodDistances: number[] = [50, 100, 200],\n enabled: boolean = true\n ) {\n this.camera = camera;\n this.lodDistances = lodDistances;\n this.enabled = enabled;\n }\n\n /**\n * Gets the LOD level for a position based on distance from camera\n */\n getLODLevel(position: Vector3Data): LODLevel {\n if (!this.enabled) {\n return LODLevelEnum.HIGH;\n }\n\n const dx = position.x - this.camera.position.x;\n const dy = position.y - this.camera.position.y;\n const dz = position.z - this.camera.position.z;\n const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n if (distance < this.lodDistances[0]) {\n return LODLevelEnum.HIGH;\n } else if (distance < this.lodDistances[1]) {\n return LODLevelEnum.MEDIUM;\n } else {\n return LODLevelEnum.LOW;\n }\n }\n\n /**\n * Checks if a node should be visible based on distance\n */\n shouldRenderNode(position: Vector3Data, maxDistance: number = 500): boolean {\n const dx = position.x - this.camera.position.x;\n const dy = position.y - this.camera.position.y;\n const dz = position.z - this.camera.position.z;\n const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n return distance < maxDistance;\n }\n\n /**\n * Sets the LOD distances\n */\n setLODDistances(distances: number[]): void {\n this.lodDistances = distances;\n }\n\n /**\n * Enables/disables LOD\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n}\n","import * as THREE from 'three';\nimport type { Vector3Data } from '../utils/types';\n\n/**\n * Frustum Culler\n * Determines which objects are visible in the camera's viewport\n */\nexport class FrustumCuller {\n private camera: THREE.PerspectiveCamera;\n private frustum: THREE.Frustum;\n private projScreenMatrix: THREE.Matrix4;\n private enabled: boolean;\n\n constructor(camera: THREE.PerspectiveCamera, enabled: boolean = true) {\n this.camera = camera;\n this.frustum = new THREE.Frustum();\n this.projScreenMatrix = new THREE.Matrix4();\n this.enabled = enabled;\n }\n\n /**\n * Updates the frustum from the camera\n */\n update(): void {\n this.projScreenMatrix.multiplyMatrices(\n this.camera.projectionMatrix,\n this.camera.matrixWorldInverse\n );\n this.frustum.setFromProjectionMatrix(this.projScreenMatrix);\n }\n\n /**\n * Checks if a point is inside the frustum\n */\n isPointVisible(position: Vector3Data): boolean {\n if (!this.enabled) return true;\n\n const point = new THREE.Vector3(position.x, position.y, position.z);\n return this.frustum.containsPoint(point);\n }\n\n /**\n * Checks if a sphere is inside or intersects the frustum\n */\n isSphereVisible(position: Vector3Data, radius: number): boolean {\n if (!this.enabled) return true;\n\n const sphere = new THREE.Sphere(\n new THREE.Vector3(position.x, position.y, position.z),\n radius\n );\n return this.frustum.intersectsSphere(sphere);\n }\n\n /**\n * Checks if a line segment is potentially visible\n */\n isLineVisible(start: Vector3Data, end: Vector3Data): boolean {\n if (!this.enabled) return true;\n\n // Quick check: if either endpoint is visible, the line might be visible\n const startPoint = new THREE.Vector3(start.x, start.y, start.z);\n const endPoint = new THREE.Vector3(end.x, end.y, end.z);\n\n if (this.frustum.containsPoint(startPoint) || this.frustum.containsPoint(endPoint)) {\n return true;\n }\n\n // Create a bounding sphere around the line\n const center = new THREE.Vector3(\n (start.x + end.x) / 2,\n (start.y + end.y) / 2,\n (start.z + end.z) / 2\n );\n const radius = center.distanceTo(startPoint);\n const sphere = new THREE.Sphere(center, radius);\n\n return this.frustum.intersectsSphere(sphere);\n }\n\n /**\n * Enables/disables frustum culling\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n}\n","import * as THREE from 'three';\nimport { SceneManager } from '../core/SceneManager';\nimport type { NodeData, Edge } from '../utils/types';\n\n/**\n * Edge hover info returned by raycaster\n */\nexport interface EdgeHoverInfo {\n edge: Edge;\n sourceNode: NodeData;\n targetNode: NodeData;\n edgeLine: THREE.Line;\n}\n\n/**\n * Raycaster Manager\n * Handles click and hover detection on nodes and edges\n */\nexport class RaycasterManager {\n private sceneManager: SceneManager;\n private raycaster: THREE.Raycaster;\n private mouse: THREE.Vector2;\n private container: HTMLElement;\n\n private onNodeClick: ((nodeData: NodeData) => void) | null = null;\n private onNodeHover: ((nodeData: NodeData | null) => void) | null = null;\n private onEdgeHover: ((info: EdgeHoverInfo | null) => void) | null = null;\n private onEdgeClick: ((info: EdgeHoverInfo) => void) | null = null;\n\n private hoveredNodeId: string | null = null;\n private hoveredEdgeKey: string | null = null;\n\n private nodeObjects: THREE.Object3D[] = [];\n private edgeObjects: THREE.Line[] = [];\n\n constructor(sceneManager: SceneManager, container: HTMLElement) {\n this.sceneManager = sceneManager;\n this.container = container;\n this.raycaster = new THREE.Raycaster();\n this.raycaster.params.Line = { threshold: 1.5 }; // Increased threshold for easier relationship clicking\n this.mouse = new THREE.Vector2();\n\n // Bind event handlers\n this.handleClick = this.handleClick.bind(this);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n\n // Add event listeners\n container.addEventListener('click', this.handleClick);\n container.addEventListener('mousemove', this.handleMouseMove);\n }\n\n /**\n * Updates the list of node objects to raycast against\n */\n setNodeObjects(objects: THREE.Object3D[]): void {\n this.nodeObjects = objects;\n }\n\n /**\n * Updates the list of edge objects to raycast against\n */\n setEdgeObjects(objects: THREE.Line[]): void {\n this.edgeObjects = objects;\n }\n\n /**\n * Sets the click callback\n */\n setClickCallback(callback: ((nodeData: NodeData) => void) | null): void {\n this.onNodeClick = callback;\n }\n\n /**\n * Sets the node hover callback\n */\n setHoverCallback(callback: ((nodeData: NodeData | null) => void) | null): void {\n this.onNodeHover = callback;\n }\n\n /**\n * Sets the edge hover callback\n */\n setEdgeHoverCallback(callback: ((info: EdgeHoverInfo | null) => void) | null): void {\n this.onEdgeHover = callback;\n }\n\n /**\n * Sets the edge click callback\n */\n setEdgeClickCallback(callback: ((info: EdgeHoverInfo) => void) | null): void {\n this.onEdgeClick = callback;\n }\n\n /**\n * Handles click events\n */\n private handleClick(event: MouseEvent): void {\n // Check for node click first (priority over edges)\n const nodeData = this.getIntersectedNode(event);\n\n if (nodeData && this.onNodeClick) {\n this.onNodeClick(nodeData);\n return;\n }\n\n // Check for edge click if no node was clicked\n const edgeInfo = this.getIntersectedEdge(event);\n if (edgeInfo && this.onEdgeClick) {\n this.onEdgeClick(edgeInfo);\n }\n }\n\n /**\n * Handles mouse move events for hover detection\n */\n private handleMouseMove(event: MouseEvent): void {\n // Check node hover first (priority over edges)\n const nodeData = this.getIntersectedNode(event);\n const newHoveredNodeId = nodeData?.id ?? null;\n\n if (newHoveredNodeId !== this.hoveredNodeId) {\n this.hoveredNodeId = newHoveredNodeId;\n\n if (this.onNodeHover) {\n this.onNodeHover(nodeData);\n }\n }\n\n // If hovering a node, clear edge hover\n if (nodeData) {\n if (this.hoveredEdgeKey !== null && this.onEdgeHover) {\n this.hoveredEdgeKey = null;\n this.onEdgeHover(null);\n }\n this.container.style.cursor = 'pointer';\n return;\n }\n\n // Check edge hover\n const edgeInfo = this.getIntersectedEdge(event);\n const newHoveredEdgeKey = edgeInfo ? `${edgeInfo.edge.source}-${edgeInfo.edge.target}` : null;\n\n if (newHoveredEdgeKey !== this.hoveredEdgeKey) {\n this.hoveredEdgeKey = newHoveredEdgeKey;\n\n if (this.onEdgeHover) {\n this.onEdgeHover(edgeInfo);\n }\n }\n\n // Update cursor\n this.container.style.cursor = edgeInfo ? 'pointer' : 'default';\n }\n\n /**\n * Gets the intersected node from a mouse event\n */\n private getIntersectedNode(event: MouseEvent): NodeData | null {\n const rect = this.container.getBoundingClientRect();\n\n this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;\n\n this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);\n\n // Check all node groups\n const intersects = this.raycaster.intersectObjects(this.nodeObjects, true);\n\n if (intersects.length > 0) {\n // Find the parent group that contains the nodeData\n let obj: THREE.Object3D | null = intersects[0].object;\n\n while (obj) {\n if (obj.userData?.nodeData) {\n return obj.userData.nodeData as NodeData;\n }\n obj = obj.parent;\n }\n }\n\n return null;\n }\n\n /**\n * Gets the intersected edge from a mouse event\n */\n private getIntersectedEdge(event: MouseEvent): EdgeHoverInfo | null {\n const rect = this.container.getBoundingClientRect();\n\n this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;\n\n this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);\n\n // Check edge lines\n const intersects = this.raycaster.intersectObjects(this.edgeObjects, false);\n\n if (intersects.length > 0) {\n const line = intersects[0].object as THREE.Line;\n const userData = line.userData;\n\n if (userData?.edge && userData?.sourceNode && userData?.targetNode) {\n return {\n edge: userData.edge as Edge,\n sourceNode: userData.sourceNode as NodeData,\n targetNode: userData.targetNode as NodeData,\n edgeLine: line,\n };\n }\n }\n\n return null;\n }\n\n /**\n * Performs a raycast and returns the intersected node ID\n */\n getIntersectedNodeId(screenX: number, screenY: number): string | null {\n const rect = this.container.getBoundingClientRect();\n\n this.mouse.x = ((screenX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((screenY - rect.top) / rect.height) * 2 + 1;\n\n this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);\n\n const intersects = this.raycaster.intersectObjects(this.nodeObjects, true);\n\n if (intersects.length > 0) {\n let obj: THREE.Object3D | null = intersects[0].object;\n\n while (obj) {\n if (obj.userData?.nodeId) {\n return obj.userData.nodeId as string;\n }\n obj = obj.parent;\n }\n }\n\n return null;\n }\n\n /**\n * Dispose resources and remove event listeners\n */\n dispose(): void {\n this.container.removeEventListener('click', this.handleClick);\n this.container.removeEventListener('mousemove', this.handleMouseMove);\n }\n}\n","import type { NodeData } from '../utils/types';\n\n/**\n * Panel Manager\n * Handles the glassmorphic info panel for nodes\n */\nexport class PanelManager {\n private container: HTMLElement;\n private panel: HTMLElement | null = null;\n private currentNodeId: string | null = null;\n private visible: boolean = false;\n\n private panelTemplate: ((nodeData: NodeData, neighbors: NodeData[]) => string) | null = null;\n private panelStyles: Record<string, string> = {};\n private onExpand: ((nodeId: string, depth: number) => void) | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n this.createPanel();\n }\n\n /**\n * Creates the panel element\n */\n private createPanel(): void {\n this.panel = document.createElement('div');\n this.panel.className = 'force-graph-panel';\n this.panel.style.cssText = `\n position: absolute;\n right: 20px;\n top: 50%;\n transform: translateY(-50%);\n width: 280px;\n max-height: 80vh;\n overflow-y: auto;\n background: rgba(15, 15, 25, 0.85);\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n padding: 24px;\n color: white;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n box-shadow: \n 0 8px 32px rgba(0, 0, 0, 0.4),\n inset 0 0 0 1px rgba(255, 255, 255, 0.05);\n z-index: 1000;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease, transform 0.3s ease;\n `;\n\n // Apply custom styles\n Object.entries(this.panelStyles).forEach(([key, value]) => {\n this.panel!.style.setProperty(key, value);\n });\n\n this.container.appendChild(this.panel);\n }\n\n /**\n * Sets the panel template function\n */\n setPanelTemplate(template: ((nodeData: NodeData, neighbors: NodeData[]) => string) | null): void {\n this.panelTemplate = template;\n }\n\n /**\n * Sets custom panel styles\n */\n setPanelStyles(styles: Record<string, string>): void {\n this.panelStyles = styles;\n if (this.panel) {\n Object.entries(styles).forEach(([key, value]) => {\n this.panel!.style.setProperty(key, value);\n });\n }\n }\n\n /**\n * Sets the expand callback\n */\n setExpandCallback(callback: ((nodeId: string, depth: number) => void) | null): void {\n this.onExpand = callback;\n }\n\n /**\n * Shows the panel with node information\n */\n show(nodeData: NodeData, neighbors: NodeData[]): void {\n if (!this.panel) return;\n\n this.currentNodeId = nodeData.id;\n\n // Generate content\n let content: string;\n\n if (this.panelTemplate) {\n content = this.panelTemplate(nodeData, neighbors);\n } else {\n content = this.generateDefaultContent(nodeData, neighbors);\n }\n\n this.panel.innerHTML = content;\n\n // Attach event listeners to buttons\n const expandBtn = this.panel.querySelector('[data-action=\"expand\"]');\n const depthSelect = this.panel.querySelector('[data-depth-select]') as HTMLSelectElement;\n if (expandBtn && this.onExpand) {\n expandBtn.addEventListener('click', () => {\n if (this.currentNodeId) {\n const depth = depthSelect ? parseInt(depthSelect.value, 10) : 1;\n this.onExpand!(this.currentNodeId, depth);\n }\n });\n }\n\n const closeBtn = this.panel.querySelector('[data-action=\"close\"]');\n if (closeBtn) {\n closeBtn.addEventListener('click', () => {\n this.hide();\n });\n }\n\n // Show panel with animation\n this.panel.style.opacity = '1';\n this.panel.style.pointerEvents = 'auto';\n this.panel.style.transform = 'translateY(-50%) translateX(0)';\n this.visible = true;\n }\n\n /**\n * Generates default panel content\n */\n private generateDefaultContent(nodeData: NodeData, neighbors: NodeData[]): string {\n const colorHex = nodeData.color\n ? `#${nodeData.color.toString(16).padStart(6, '0')}`\n : '#4A90E2';\n\n return `\n <style>\n .force-graph-panel h2 {\n margin: 0 0 16px 0;\n font-size: 20px;\n font-weight: 600;\n letter-spacing: -0.5px;\n display: flex;\n align-items: center;\n gap: 10px;\n overflow: hidden;\n }\n .force-graph-panel .node-label-text {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n }\n .force-graph-panel .color-dot {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background: ${colorHex};\n box-shadow: 0 0 10px ${colorHex}80;\n }\n .force-graph-panel .info-row {\n display: flex;\n justify-content: space-between;\n padding: 8px 0;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n font-size: 13px;\n }\n .force-graph-panel .info-row:last-child {\n border-bottom: none;\n }\n .force-graph-panel .info-label {\n color: rgba(255, 255, 255, 0.6);\n }\n .force-graph-panel .info-value {\n color: rgba(255, 255, 255, 0.95);\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 180px;\n text-align: right;\n }\n .force-graph-panel .neighbors-section {\n margin-top: 16px;\n }\n .force-graph-panel .neighbors-title {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 1px;\n color: rgba(255, 255, 255, 0.5);\n margin-bottom: 8px;\n }\n .force-graph-panel .neighbor-chip {\n display: inline-block;\n padding: 4px 10px;\n margin: 2px;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n font-size: 12px;\n }\n .force-graph-panel .depth-selector {\n margin-top: 16px;\n margin-bottom: 8px;\n }\n .force-graph-panel .depth-label {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.6);\n margin-bottom: 6px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n .force-graph-panel select {\n width: 100%;\n padding: 8px 12px;\n background: rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 6px;\n color: white;\n font-size: 13px;\n cursor: pointer;\n outline: none;\n transition: all 0.2s ease;\n }\n .force-graph-panel select:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n .force-graph-panel select:focus {\n border-color: rgba(96, 165, 250, 0.5);\n }\n .force-graph-panel .btn-row {\n display: flex;\n gap: 8px;\n margin-top: 20px;\n }\n .force-graph-panel button {\n flex: 1;\n padding: 10px 16px;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n .force-graph-panel .btn-expand {\n background: linear-gradient(135deg, #60a5fa, #a78bfa);\n color: white;\n }\n .force-graph-panel .btn-expand:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(96, 165, 250, 0.4);\n }\n .force-graph-panel .btn-close {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.8);\n }\n .force-graph-panel .btn-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n </style>\n \n <h2>\n <span class=\"color-dot\"></span>\n <span class=\"node-label-text\">${this.escapeHtml(nodeData.label)}</span>\n </h2>\n \n <div class=\"info-row\">\n <span class=\"info-label\">ID</span>\n <span class=\"info-value\" title=\"${this.escapeHtml(nodeData.id)}\">${this.escapeHtml(nodeData.id)}</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">Connections</span>\n <span class=\"info-value\">${neighbors.length}</span>\n </div>\n \n ${neighbors.length > 0 ? `\n <div class=\"neighbors-section\">\n <div class=\"neighbors-title\">Connected To</div>\n ${neighbors.slice(0, 5).map(n =>\n `<span class=\"neighbor-chip\">${this.escapeHtml(n.label)}</span>`\n ).join('')}\n ${neighbors.length > 5 ? `<span class=\"neighbor-chip\">+${neighbors.length - 5} more</span>` : ''}\n </div>\n ` : ''}\n \n <div class=\"depth-selector\">\n <div class=\"depth-label\">Expansion Depth</div>\n <select data-depth-select>\n <option value=\"1\">1 Level</option>\n <option value=\"2\">2 Levels</option>\n <option value=\"3\" selected>3 Levels</option>\n </select>\n </div>\n\n \n <div class=\"btn-row\">\n <button class=\"btn-expand\" data-action=\"expand\">Expand</button>\n <button class=\"btn-close\" data-action=\"close\">Close</button>\n </div>\n `;\n }\n\n /**\n * Escapes HTML to prevent XSS\n */\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /**\n * Hides the panel\n */\n hide(): void {\n if (!this.panel) return;\n\n this.panel.style.opacity = '0';\n this.panel.style.pointerEvents = 'none';\n this.panel.style.transform = 'translateY(-50%) translateX(20px)';\n this.visible = false;\n this.currentNodeId = null;\n }\n\n /**\n * Checks if the panel is visible\n */\n isVisible(): boolean {\n return this.visible;\n }\n\n /**\n * Gets the currently displayed node ID\n */\n getCurrentNodeId(): string | null {\n return this.currentNodeId;\n }\n\n /**\n * Dispose the panel\n */\n dispose(): void {\n if (this.panel && this.panel.parentNode) {\n this.panel.parentNode.removeChild(this.panel);\n }\n this.panel = null;\n }\n}\n","import type { Edge, NodeData } from '../utils/types';\n\n/**\n * Edge Panel Manager\n * Handles the glassmorphic info panel for edges/relationships\n */\nexport class EdgePanelManager {\n private container: HTMLElement;\n private panel: HTMLElement | null = null;\n private currentEdgeKey: string | null = null;\n private visible: boolean = false;\n\n private panelTemplate: ((edge: Edge, sourceNode: NodeData, targetNode: NodeData) => string) | null = null;\n private onClose: (() => void) | null = null;\n private onNodeClick: ((nodeId: string) => void) | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n this.createPanel();\n }\n\n /**\n * Creates the panel element\n */\n private createPanel(): void {\n this.panel = document.createElement('div');\n this.panel.className = 'force-graph-edge-panel';\n this.panel.style.cssText = `\n position: absolute;\n right: 20px;\n top: 50%;\n transform: translateY(-50%);\n width: 300px;\n max-height: 80vh;\n overflow-y: auto;\n background: rgba(15, 15, 25, 0.85);\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n padding: 24px;\n color: white;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n box-shadow: \n 0 8px 32px rgba(0, 0, 0, 0.4),\n inset 0 0 0 1px rgba(255, 255, 255, 0.05);\n z-index: 1000;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease, transform 0.3s ease;\n `;\n\n this.container.appendChild(this.panel);\n }\n\n /**\n * Sets the panel template function\n */\n setPanelTemplate(template: ((edge: Edge, sourceNode: NodeData, targetNode: NodeData) => string) | null): void {\n this.panelTemplate = template;\n }\n\n /**\n * Sets the close callback\n */\n setCloseCallback(callback: (() => void) | null): void {\n this.onClose = callback;\n }\n\n /**\n * Sets the node click callback (for navigating to nodes from edge panel)\n */\n setNodeClickCallback(callback: ((nodeId: string) => void) | null): void {\n this.onNodeClick = callback;\n }\n\n /**\n * Shows the panel with edge/relationship information\n */\n show(edge: Edge, sourceNode: NodeData, targetNode: NodeData): void {\n if (!this.panel) return;\n\n this.currentEdgeKey = `${edge.source}-${edge.target}`;\n\n // Generate content\n let content: string;\n\n if (this.panelTemplate) {\n content = this.panelTemplate(edge, sourceNode, targetNode);\n } else {\n content = this.generateDefaultContent(edge, sourceNode, targetNode);\n }\n\n this.panel.innerHTML = content;\n\n // Attach event listeners\n const closeBtn = this.panel.querySelector('[data-action=\"close\"]');\n if (closeBtn) {\n closeBtn.addEventListener('click', () => {\n this.hide();\n if (this.onClose) {\n this.onClose();\n }\n });\n }\n\n // Node click handlers\n const sourceBtn = this.panel.querySelector('[data-action=\"goto-source\"]');\n if (sourceBtn && this.onNodeClick) {\n sourceBtn.addEventListener('click', () => {\n if (this.onNodeClick) {\n this.onNodeClick(edge.source);\n }\n });\n }\n\n const targetBtn = this.panel.querySelector('[data-action=\"goto-target\"]');\n if (targetBtn && this.onNodeClick) {\n targetBtn.addEventListener('click', () => {\n if (this.onNodeClick) {\n this.onNodeClick(edge.target);\n }\n });\n }\n\n // Show panel with animation\n this.panel.style.opacity = '1';\n this.panel.style.pointerEvents = 'auto';\n this.panel.style.transform = 'translateY(-50%) translateX(0)';\n this.visible = true;\n }\n\n /**\n * Generates default panel content\n */\n private generateDefaultContent(edge: Edge, sourceNode: NodeData, targetNode: NodeData): string {\n const sourceColorHex = sourceNode.color\n ? `#${sourceNode.color.toString(16).padStart(6, '0')}`\n : '#ff9966';\n const targetColorHex = targetNode.color\n ? `#${targetNode.color.toString(16).padStart(6, '0')}`\n : '#ff9966';\n\n const relationship = edge.relationship || 'connected to';\n\n return `\n <style>\n .force-graph-edge-panel .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 20px;\n }\n .force-graph-edge-panel .panel-title {\n font-size: 14px;\n text-transform: uppercase;\n letter-spacing: 1px;\n color: rgba(255, 255, 255, 0.6);\n margin: 0;\n }\n .force-graph-edge-panel .relationship-section {\n background: rgba(255, 255, 255, 0.05);\n border-radius: 12px;\n padding: 16px;\n text-align: center;\n margin-bottom: 20px;\n }\n .force-graph-edge-panel .relationship-label {\n font-size: 18px;\n font-weight: 600;\n color: #a78bfa;\n letter-spacing: 0.5px;\n }\n .force-graph-edge-panel .node-card {\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n padding: 14px;\n margin-bottom: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n .force-graph-edge-panel .node-card:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n transform: translateX(4px);\n }\n .force-graph-edge-panel .node-card-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 6px;\n }\n .force-graph-edge-panel .node-type {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 1px;\n color: rgba(255, 255, 255, 0.5);\n }\n .force-graph-edge-panel .color-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n .force-graph-edge-panel .node-label {\n font-size: 15px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.95);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .force-graph-edge-panel .connection-arrow {\n text-align: center;\n color: rgba(255, 255, 255, 0.4);\n font-size: 18px;\n margin: 8px 0;\n }\n .force-graph-edge-panel .btn-close {\n width: 100%;\n padding: 12px 16px;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.8);\n margin-top: 16px;\n }\n .force-graph-edge-panel .btn-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n .force-graph-edge-panel .hint-text {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n text-align: center;\n margin-top: 8px;\n }\n </style>\n \n <div class=\"panel-header\">\n <h3 class=\"panel-title\">Relationship</h3>\n </div>\n \n <div class=\"relationship-section\">\n <span class=\"relationship-label\">${this.escapeHtml(relationship)}</span>\n </div>\n \n <div class=\"node-card\" data-action=\"goto-source\" title=\"Click to focus on ${this.escapeHtml(sourceNode.label)}\">\n <div class=\"node-type\">Source</div>\n <div class=\"node-card-header\">\n <span class=\"color-dot\" style=\"background: ${sourceColorHex}; box-shadow: 0 0 8px ${sourceColorHex}80;\"></span>\n <span class=\"node-label\">${this.escapeHtml(sourceNode.label)}</span>\n </div>\n </div>\n \n <div class=\"connection-arrow\">↓</div>\n \n <div class=\"node-card\" data-action=\"goto-target\" title=\"Click to focus on ${this.escapeHtml(targetNode.label)}\">\n <div class=\"node-type\">Target</div>\n <div class=\"node-card-header\">\n <span class=\"color-dot\" style=\"background: ${targetColorHex}; box-shadow: 0 0 8px ${targetColorHex}80;\"></span>\n <span class=\"node-label\">${this.escapeHtml(targetNode.label)}</span>\n </div>\n </div>\n \n <p class=\"hint-text\">Click on a node to focus on it</p>\n \n <button class=\"btn-close\" data-action=\"close\">Close</button>\n `;\n }\n\n /**\n * Escapes HTML to prevent XSS\n */\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /**\n * Hides the panel\n */\n hide(): void {\n if (!this.panel) return;\n\n this.panel.style.opacity = '0';\n this.panel.style.pointerEvents = 'none';\n this.panel.style.transform = 'translateY(-50%) translateX(20px)';\n this.visible = false;\n this.currentEdgeKey = null;\n }\n\n /**\n * Checks if the panel is visible\n */\n isVisible(): boolean {\n return this.visible;\n }\n\n /**\n * Gets the currently displayed edge key\n */\n getCurrentEdgeKey(): string | null {\n return this.currentEdgeKey;\n }\n\n /**\n * Dispose the panel\n */\n dispose(): void {\n if (this.panel && this.panel.parentNode) {\n this.panel.parentNode.removeChild(this.panel);\n }\n this.panel = null;\n }\n}\n","import type { Edge, NodeData } from '../utils/types';\n\n/**\n * Edge Tooltip Manager\n * Shows relationship info when hovering over edges\n */\nexport class EdgeTooltipManager {\n private tooltip: HTMLElement | null = null;\n private visible: boolean = false;\n\n constructor() {\n this.createTooltip();\n this.setupMouseTracking();\n }\n\n /**\n * Creates the tooltip element\n */\n private createTooltip(): void {\n this.tooltip = document.createElement('div');\n this.tooltip.className = 'force-graph-edge-tooltip';\n this.tooltip.style.cssText = `\n position: fixed;\n padding: 10px 14px;\n background: rgba(30, 30, 30, 0.95);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 8px;\n color: white;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 13px;\n pointer-events: none;\n z-index: 10000;\n opacity: 0;\n transform: translateY(5px);\n transition: opacity 0.15s ease, transform 0.15s ease;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n max-width: 400px;\n white-space: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n `;\n\n document.body.appendChild(this.tooltip);\n }\n\n /**\n * Sets up mouse tracking for tooltip following\n */\n private setupMouseTracking(): void {\n document.addEventListener('mousemove', (e) => {\n if (this.visible && this.tooltip) {\n this.positionTooltip(e.clientX, e.clientY);\n }\n });\n }\n\n /**\n * Positions the tooltip near the mouse\n */\n private positionTooltip(mouseX: number, mouseY: number): void {\n if (!this.tooltip) return;\n\n const tooltipRect = this.tooltip.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let left = mouseX + 15;\n let top = mouseY + 15;\n\n // Keep tooltip within viewport bounds\n if (left + tooltipRect.width > viewportWidth - 10) {\n left = mouseX - tooltipRect.width - 15;\n }\n if (top + tooltipRect.height > viewportHeight - 10) {\n top = mouseY - tooltipRect.height - 15;\n }\n if (left < 10) {\n left = 10;\n }\n if (top < 10) {\n top = 10;\n }\n\n this.tooltip.style.left = `${left}px`;\n this.tooltip.style.top = `${top}px`;\n }\n\n /**\n * Shows the tooltip with edge info\n */\n show(\n edge: Edge,\n sourceNode: NodeData,\n targetNode: NodeData,\n mouseX: number,\n mouseY: number\n ): void {\n if (!this.tooltip) return;\n\n const relationship = edge.relationship || 'connected to';\n\n // Generate content with proper text wrapping\n this.tooltip.innerHTML = `\n <div style=\"display: flex; flex-direction: column; gap: 4px;\">\n <div style=\"display: flex; align-items: center; gap: 6px; flex-wrap: wrap;\">\n <span style=\"font-weight: 600; color: #ff9966;\">${this.escapeHtml(sourceNode.label)}</span>\n </div>\n <div style=\"color: rgba(255, 255, 255, 0.6); font-style: italic; font-size: 12px; padding-left: 8px;\">\n ↳ ${this.escapeHtml(relationship)}\n </div>\n <div style=\"display: flex; align-items: center; gap: 6px; flex-wrap: wrap;\">\n <span style=\"font-weight: 600; color: #ff9966;\">${this.escapeHtml(targetNode.label)}</span>\n </div>\n </div>\n `;\n\n // Position and show\n this.positionTooltip(mouseX, mouseY);\n this.tooltip.style.opacity = '1';\n this.tooltip.style.transform = 'translateY(0)';\n this.visible = true;\n }\n\n /**\n * Updates tooltip position (called externally on mouse move)\n */\n updatePosition(mouseX: number, mouseY: number): void {\n if (this.visible) {\n this.positionTooltip(mouseX, mouseY);\n }\n }\n\n /**\n * Hides the tooltip\n */\n hide(): void {\n if (!this.tooltip) return;\n\n this.tooltip.style.opacity = '0';\n this.tooltip.style.transform = 'translateY(5px)';\n this.visible = false;\n }\n\n /**\n * Checks if tooltip is visible\n */\n isVisible(): boolean {\n return this.visible;\n }\n\n /**\n * Escapes HTML to prevent XSS\n */\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /**\n * Dispose the tooltip\n */\n dispose(): void {\n if (this.tooltip && this.tooltip.parentNode) {\n this.tooltip.parentNode.removeChild(this.tooltip);\n }\n this.tooltip = null;\n }\n}\n","import type { NodeData, Edge } from '../utils/types';\n\n/**\n * Search Manager\n * Handles the glassmorphic search UI and results dropdown\n */\nexport class SearchManager {\n private container: HTMLElement;\n private searchContainer: HTMLElement | null = null;\n private searchInput: HTMLInputElement | null = null;\n private searchResults: HTMLElement | null = null;\n private searchTimeout: number | null = null;\n private placeholder: string;\n\n private onSearch: (query: string) => { nodeResults: NodeData[], edgeResults: Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> };\n private onResultClick: (nodeId: string) => void;\n\n constructor(\n container: HTMLElement,\n options: {\n placeholder?: string,\n onSearch: (query: string) => { nodeResults: NodeData[], edgeResults: Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> },\n onResultClick: (nodeId: string) => void\n }\n ) {\n this.container = container;\n this.placeholder = options.placeholder || 'Search nodes or relationships...';\n this.onSearch = options.onSearch;\n this.onResultClick = options.onResultClick;\n this.init();\n }\n\n private init(): void {\n this.createSearchUI();\n this.addEventListeners();\n }\n\n private createSearchUI(): void {\n // Create search container\n this.searchContainer = document.createElement('div');\n this.searchContainer.className = 'f3d-search-container';\n Object.assign(this.searchContainer.style, {\n position: 'absolute',\n top: '20px',\n left: '175px', // Adjusted to make room for view toggle\n zIndex: '100',\n width: '320px'\n });\n\n // Create input wrapper\n const wrapper = document.createElement('div');\n wrapper.className = 'f3d-search-input-wrapper';\n Object.assign(wrapper.style, {\n position: 'relative',\n display: 'flex',\n alignItems: 'center'\n });\n\n // Add Search Icon (SVG)\n wrapper.innerHTML = `\n <svg class=\"f3d-search-icon\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" \n stroke-width=\"2\" style=\"position: absolute; left: 14px; z-index: 10; color: rgba(255, 255, 255, 0.5); pointer-events: none;\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.35-4.35\"></path>\n </svg>\n `;\n\n // Create input\n this.searchInput = document.createElement('input');\n this.searchInput.type = 'text';\n this.searchInput.className = 'f3d-search-input';\n this.searchInput.placeholder = this.placeholder;\n this.searchInput.autocomplete = 'off';\n Object.assign(this.searchInput.style, {\n width: '100%',\n padding: '12px 16px 12px 42px',\n background: 'rgba(255, 255, 255, 0.08)',\n backdropFilter: 'blur(20px)',\n webkitBackdropFilter: 'blur(20px)',\n border: '1px solid rgba(255, 255, 255, 0.12)',\n borderRadius: '12px',\n color: 'white',\n fontSize: '14px',\n fontFamily: 'inherit',\n outline: 'none',\n transition: 'all 0.2s ease'\n });\n\n // Add focus effect via JS (since we're adding styles inline)\n this.searchInput.addEventListener('focus', () => {\n if (this.searchInput) {\n this.searchInput.style.background = 'rgba(255, 255, 255, 0.12)';\n this.searchInput.style.borderColor = 'rgba(255, 153, 102, 0.5)';\n this.searchInput.style.boxShadow = '0 0 20px rgba(255, 153, 102, 0.15)';\n }\n });\n this.searchInput.addEventListener('blur', () => {\n if (this.searchInput) {\n this.searchInput.style.background = 'rgba(255, 255, 255, 0.08)';\n this.searchInput.style.borderColor = 'rgba(255, 255, 255, 0.12)';\n this.searchInput.style.boxShadow = 'none';\n }\n });\n\n // Create results dropdown\n this.searchResults = document.createElement('div');\n this.searchResults.className = 'f3d-search-results';\n Object.assign(this.searchResults.style, {\n position: 'absolute',\n top: '100%',\n left: '0',\n right: '0',\n marginTop: '8px',\n background: 'rgba(20, 20, 25, 0.95)',\n backdropFilter: 'blur(20px)',\n webkitBackdropFilter: 'blur(20px)',\n border: '1px solid rgba(255, 255, 255, 0.1)',\n borderRadius: '12px',\n maxHeight: '300px',\n overflowY: 'auto',\n display: 'none',\n boxShadow: '0 10px 40px rgba(0, 0, 0, 0.4)'\n });\n\n wrapper.appendChild(this.searchInput);\n this.searchContainer.appendChild(wrapper);\n this.searchContainer.appendChild(this.searchResults);\n this.container.appendChild(this.searchContainer);\n\n // Add some CSS for the list items\n const style = document.createElement('style');\n style.textContent = `\n .f3d-search-result-item {\n padding: 10px 14px;\n cursor: pointer;\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n transition: background 0.15s ease;\n }\n .f3d-search-result-item:hover {\n background: rgba(255, 153, 102, 0.15);\n }\n .f3d-search-result-item:last-child {\n border-bottom: none;\n }\n .f3d-result-label {\n color: white;\n font-size: 13px;\n font-weight: 500;\n margin-bottom: 2px;\n }\n .f3d-result-type {\n color: rgba(255, 153, 102, 0.8);\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n .f3d-result-relationship {\n color: rgba(255, 255, 255, 0.5);\n font-size: 11px;\n font-style: italic;\n }\n .f3d-no-results {\n padding: 14px;\n color: rgba(255, 255, 255, 0.4);\n font-size: 13px;\n text-align: center;\n }\n .f3d-search-section-header {\n padding: 8px 14px 6px;\n color: rgba(255, 255, 255, 0.3);\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 1px;\n font-weight: 600;\n background: rgba(0, 0, 0, 0.2);\n }\n .f3d-search-results::-webkit-scrollbar { width: 6px; }\n .f3d-search-results::-webkit-scrollbar-track { background: transparent; }\n .f3d-search-results::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 3px; }\n .f3d-search-results::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.25); }\n `;\n document.head.appendChild(style);\n }\n\n private addEventListeners(): void {\n if (!this.searchInput || !this.searchResults) return;\n\n this.searchInput.addEventListener('input', (e) => {\n const query = (e.target as HTMLInputElement).value;\n\n if (this.searchTimeout) window.clearTimeout(this.searchTimeout);\n this.searchTimeout = window.setTimeout(() => {\n this.performSearch(query);\n }, 150);\n });\n\n this.searchInput.addEventListener('focus', () => {\n if (this.searchInput && this.searchInput.value.length > 0) {\n this.searchResults!.style.display = 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (this.searchContainer && !this.searchContainer.contains(e.target as Node)) {\n if (this.searchResults) this.searchResults.style.display = 'none';\n }\n });\n }\n\n private performSearch(query: string): void {\n if (!this.searchResults) return;\n\n if (query.trim().length === 0) {\n this.searchResults.style.display = 'none';\n return;\n }\n\n const { nodeResults, edgeResults } = this.onSearch(query);\n\n if (nodeResults.length === 0 && edgeResults.length === 0) {\n this.searchResults.innerHTML = '<div class=\"f3d-no-results\">No results found</div>';\n this.searchResults.style.display = 'block';\n return;\n }\n\n let html = '';\n\n // Node results\n if (nodeResults.length > 0) {\n html += '<div class=\"f3d-search-section-header\">Nodes</div>';\n nodeResults.slice(0, 10).forEach(node => {\n const typeLabel = (node.type as string) || 'Node';\n html += `\n <div class=\"f3d-search-result-item\" data-node-id=\"${this.escapeHtml(node.id)}\">\n <div class=\"f3d-result-label\">${this.escapeHtml(node.label)}</div>\n <div class=\"f3d-result-type\">${this.escapeHtml(typeLabel)}</div>\n </div>\n `;\n });\n if (nodeResults.length > 10) {\n html += `<div class=\"f3d-no-results\">+ ${nodeResults.length - 10} more nodes</div>`;\n }\n }\n\n // Edge results\n if (edgeResults.length > 0) {\n html += '<div class=\"f3d-search-section-header\">Relationships</div>';\n edgeResults.slice(0, 5).forEach(({ edge, sourceNode, targetNode }) => {\n html += `\n <div class=\"f3d-search-result-item\" data-node-id=\"${this.escapeHtml(edge.source as string)}\">\n <div class=\"f3d-result-label\">${this.escapeHtml(sourceNode.label)} → ${this.escapeHtml(targetNode.label)}</div>\n <div class=\"f3d-result-relationship\">${this.escapeHtml((edge.relationship as string) || 'connected')}</div>\n </div>\n `;\n });\n if (edgeResults.length > 5) {\n html += `<div class=\"f3d-no-results\">+ ${edgeResults.length - 5} more relationships</div>`;\n }\n }\n\n this.searchResults.innerHTML = html;\n this.searchResults.style.display = 'block';\n\n // Add click handlers\n this.searchResults.querySelectorAll('.f3d-search-result-item').forEach(item => {\n item.addEventListener('click', () => {\n const nodeId = (item as HTMLElement).dataset.nodeId;\n if (nodeId) {\n this.onResultClick(nodeId);\n if (this.searchResults) this.searchResults.style.display = 'none';\n if (this.searchInput) {\n this.searchInput.blur();\n }\n }\n });\n });\n }\n\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n public dispose(): void {\n if (this.searchContainer && this.searchContainer.parentNode) {\n this.searchContainer.parentNode.removeChild(this.searchContainer);\n }\n }\n}\n","/**\n * View Toggle Manager\n * Handles the 2D/3D view toggle button with glassmorphic styling\n */\nexport type ViewMode = '2d' | '3d';\n\nexport class ViewToggleManager {\n private container: HTMLElement;\n private toggleContainer: HTMLElement | null = null;\n private currentMode: ViewMode = '3d';\n private onViewChange: (mode: ViewMode) => void;\n\n constructor(\n container: HTMLElement,\n options: {\n initialMode?: ViewMode;\n onViewChange: (mode: ViewMode) => void;\n }\n ) {\n this.container = container;\n this.currentMode = options.initialMode || '3d';\n this.onViewChange = options.onViewChange;\n this.init();\n }\n\n private init(): void {\n this.createToggleUI();\n }\n\n private createToggleUI(): void {\n // Create toggle container\n this.toggleContainer = document.createElement('div');\n this.toggleContainer.className = 'f3d-view-toggle';\n Object.assign(this.toggleContainer.style, {\n position: 'absolute',\n top: '20px',\n left: '20px',\n zIndex: '100',\n display: 'flex',\n gap: '0',\n background: 'rgba(255, 255, 255, 0.08)',\n backdropFilter: 'blur(20px)',\n WebkitBackdropFilter: 'blur(20px)',\n border: '1px solid rgba(255, 255, 255, 0.12)',\n borderRadius: '12px',\n padding: '5px',\n boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)'\n });\n\n // Create 2D button\n const btn2D = this.createButton('2D', '2d');\n const btn3D = this.createButton('3D', '3d');\n\n this.toggleContainer.appendChild(btn2D);\n this.toggleContainer.appendChild(btn3D);\n this.container.appendChild(this.toggleContainer);\n\n // Update initial state\n this.updateButtonStates();\n\n // Add CSS for hover/active states\n const style = document.createElement('style');\n style.textContent = `\n .f3d-view-btn {\n padding: 8px 16px;\n background: transparent;\n border: none;\n color: rgba(255, 255, 255, 0.5);\n font-size: 12px;\n font-weight: 600;\n font-family: inherit;\n letter-spacing: 0.5px;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: 8px;\n min-width: 44px;\n }\n .f3d-view-btn:hover {\n color: rgba(255, 255, 255, 0.8);\n }\n .f3d-view-btn.active {\n background: linear-gradient(135deg, rgba(255, 153, 102, 0.3), rgba(255, 102, 153, 0.2));\n color: white;\n box-shadow: 0 0 15px rgba(255, 153, 102, 0.2);\n }\n .f3d-view-btn:focus {\n outline: none;\n }\n `;\n document.head.appendChild(style);\n }\n\n private createButton(label: string, mode: ViewMode): HTMLButtonElement {\n const btn = document.createElement('button');\n btn.className = 'f3d-view-btn';\n btn.dataset.mode = mode;\n btn.innerHTML = this.getIcon(mode) + `<span style=\"margin-left: 4px;\">${label}</span>`;\n btn.style.display = 'flex';\n btn.style.alignItems = 'center';\n btn.style.justifyContent = 'center';\n\n btn.addEventListener('click', () => {\n if (this.currentMode !== mode) {\n this.currentMode = mode;\n this.updateButtonStates();\n this.onViewChange(mode);\n }\n });\n\n return btn;\n }\n\n private getIcon(mode: ViewMode): string {\n if (mode === '2d') {\n // Grid/2D icon\n return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"></rect>\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"></rect>\n <rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"></rect>\n <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"></rect>\n </svg>`;\n } else {\n // Cube/3D icon\n return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\"></path>\n <polyline points=\"3.27 6.96 12 12.01 20.73 6.96\"></polyline>\n <line x1=\"12\" y1=\"22.08\" x2=\"12\" y2=\"12\"></line>\n </svg>`;\n }\n }\n\n private updateButtonStates(): void {\n if (!this.toggleContainer) return;\n\n const buttons = this.toggleContainer.querySelectorAll('.f3d-view-btn');\n buttons.forEach((btn) => {\n const mode = (btn as HTMLElement).dataset.mode as ViewMode;\n if (mode === this.currentMode) {\n btn.classList.add('active');\n } else {\n btn.classList.remove('active');\n }\n });\n }\n\n public setMode(mode: ViewMode): void {\n if (this.currentMode !== mode) {\n this.currentMode = mode;\n this.updateButtonStates();\n }\n }\n\n public getMode(): ViewMode {\n return this.currentMode;\n }\n\n public dispose(): void {\n if (this.toggleContainer && this.toggleContainer.parentNode) {\n this.toggleContainer.parentNode.removeChild(this.toggleContainer);\n }\n }\n}\n","import type { NodeData, Edge, InternalNode } from '../utils/types';\n\n/**\n * 2D Node representation\n */\ninterface Node2D {\n id: string;\n label: string;\n x: number;\n y: number;\n vx: number;\n vy: number;\n color: number;\n radius: number;\n data: NodeData;\n}\n\n/**\n * 2D Edge representation\n */\ninterface Edge2D {\n source: string;\n target: string;\n relationship?: string;\n data: Edge;\n}\n\n/**\n * Transform state for pan/zoom\n */\ninterface Transform {\n x: number;\n y: number;\n scale: number;\n}\n\n/**\n * ForceGraph2D Options\n */\nexport interface ForceGraph2DOptions {\n backgroundColor?: string;\n gridColor?: string;\n nodeRadius?: number;\n edgeColor?: string;\n edgeOpacity?: number;\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n onNodeClick?: (node: NodeData) => void;\n onNodeHover?: (node: NodeData | null) => void;\n onEdgeHover?: (edge: Edge | null, event?: MouseEvent) => void;\n onEdgeClick?: (edge: Edge) => void;\n}\n\nconst DEFAULT_2D_OPTIONS: Required<Omit<ForceGraph2DOptions, 'onNodeClick' | 'onNodeHover' | 'onEdgeHover' | 'onEdgeClick'>> = {\n backgroundColor: '#0a0a0a',\n gridColor: 'rgba(255, 255, 255, 0.03)',\n nodeRadius: 24,\n edgeColor: 'rgba(255, 255, 255, 0.15)',\n edgeOpacity: 0.4,\n repulsionStrength: 5000, // Strong repulsion for spread out layout\n attractionStrength: 0.001, // Very low attraction\n damping: 0.85 // Fast energy dissipation\n};\n\n/**\n * ForceGraph2D\n * 2D Canvas-based force-directed graph renderer with premium aesthetics\n */\nexport class ForceGraph2D {\n private container: HTMLElement;\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n private options: Required<Omit<ForceGraph2DOptions, 'onNodeClick' | 'onNodeHover' | 'onEdgeHover' | 'onEdgeClick'>> & ForceGraph2DOptions;\n\n // Data\n private nodes: Map<string, Node2D> = new Map();\n private edges: Edge2D[] = [];\n private nodeIdToIndex: Map<string, number> = new Map();\n\n // Transform state\n private transform: Transform = { x: 0, y: 0, scale: 1 };\n\n // Interaction state\n private isDragging: boolean = false;\n private isPanning: boolean = false;\n private draggedNode: Node2D | null = null;\n private hoveredNode: Node2D | null = null;\n private hoveredEdge: Edge2D | null = null;\n private lastMousePos: { x: number; y: number } = { x: 0, y: 0 };\n private dragStartPos: { x: number; y: number } = { x: 0, y: 0 }; // Track initial click position\n private selectedNode: Node2D | null = null;\n\n // Animation\n private animationId: number | null = null;\n private isSimulating: boolean = true;\n\n // Resize handler\n private resizeHandler: () => void;\n\n constructor(container: HTMLElement, options: ForceGraph2DOptions = {}) {\n this.container = container;\n this.options = { ...DEFAULT_2D_OPTIONS, ...options };\n\n // Create canvas\n this.canvas = document.createElement('canvas');\n this.canvas.style.position = 'absolute';\n this.canvas.style.top = '0';\n this.canvas.style.left = '0';\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.canvas.style.cursor = 'grab';\n container.appendChild(this.canvas);\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get 2D context');\n }\n this.ctx = ctx;\n\n // Setup\n this.resizeHandler = this.handleResize.bind(this);\n window.addEventListener('resize', this.resizeHandler);\n this.handleResize();\n\n // Center transform\n this.transform.x = this.canvas.width / 2;\n this.transform.y = this.canvas.height / 2;\n\n // Setup interactions\n this.setupInteractions();\n\n // Start render loop\n this.startAnimation();\n }\n\n private handleResize(): void {\n const rect = this.container.getBoundingClientRect();\n const dpr = window.devicePixelRatio || 1;\n this.canvas.width = rect.width * dpr;\n this.canvas.height = rect.height * dpr;\n this.ctx.scale(dpr, dpr);\n }\n\n private setupInteractions(): void {\n // Mouse wheel for zoom\n this.canvas.addEventListener('wheel', (e) => {\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n\n const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;\n const newScale = Math.max(0.1, Math.min(5, this.transform.scale * zoomFactor));\n\n // Zoom towards mouse position\n const scaleChange = newScale / this.transform.scale;\n this.transform.x = mouseX - (mouseX - this.transform.x) * scaleChange;\n this.transform.y = mouseY - (mouseY - this.transform.y) * scaleChange;\n this.transform.scale = newScale;\n });\n\n // Mouse down\n this.canvas.addEventListener('mousedown', (e) => {\n const rect = this.canvas.getBoundingClientRect();\n const screenX = e.clientX - rect.left;\n const screenY = e.clientY - rect.top;\n const pos = this.screenToWorld(screenX, screenY);\n const node = this.findNodeAt(pos.x, pos.y);\n\n // Always save start position for click detection\n this.dragStartPos = { x: e.clientX, y: e.clientY };\n\n if (node) {\n this.isDragging = true;\n this.draggedNode = node;\n this.canvas.style.cursor = 'grabbing';\n // Restart simulation briefly when dragging\n this.isSimulating = true;\n } else {\n this.isPanning = true;\n this.canvas.style.cursor = 'grabbing';\n }\n\n this.lastMousePos = { x: e.clientX, y: e.clientY };\n });\n\n // Mouse move\n this.canvas.addEventListener('mousemove', (e) => {\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const worldPos = this.screenToWorld(mouseX, mouseY);\n\n if (this.isDragging && this.draggedNode) {\n this.draggedNode.x = worldPos.x;\n this.draggedNode.y = worldPos.y;\n this.draggedNode.vx = 0;\n this.draggedNode.vy = 0;\n } else if (this.isPanning) {\n const dx = e.clientX - this.lastMousePos.x;\n const dy = e.clientY - this.lastMousePos.y;\n this.transform.x += dx;\n this.transform.y += dy;\n this.lastMousePos = { x: e.clientX, y: e.clientY };\n } else {\n // Hover detection - check nodes first, then edges\n const node = this.findNodeAt(worldPos.x, worldPos.y);\n if (node !== this.hoveredNode) {\n this.hoveredNode = node;\n if (node) {\n // Hovering a node - clear edge hover\n if (this.hoveredEdge) {\n this.hoveredEdge = null;\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(null);\n }\n }\n this.canvas.style.cursor = 'pointer';\n if (this.options.onNodeHover) {\n this.options.onNodeHover(node.data);\n }\n } else {\n if (this.options.onNodeHover) {\n this.options.onNodeHover(null);\n }\n }\n }\n\n // Check edge hover if not hovering a node\n if (!node) {\n const edge = this.findEdgeAt(worldPos.x, worldPos.y);\n if (edge !== this.hoveredEdge) {\n this.hoveredEdge = edge;\n this.canvas.style.cursor = edge ? 'pointer' : 'grab';\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(edge ? edge.data : null, e);\n }\n }\n }\n }\n });\n\n // Mouse up\n this.canvas.addEventListener('mouseup', (e) => {\n const dx = Math.abs(e.clientX - this.dragStartPos.x);\n const dy = Math.abs(e.clientY - this.dragStartPos.y);\n const wasClick = dx < 5 && dy < 5;\n\n if (this.isDragging && this.draggedNode) {\n // Node click\n if (wasClick && this.options.onNodeClick) {\n this.selectedNode = this.draggedNode;\n this.options.onNodeClick(this.draggedNode.data);\n }\n } else if (wasClick) {\n // Check if clicked on an edge - ignore if we notably moved (covered by wasClick)\n const rect = this.canvas.getBoundingClientRect();\n const worldPos = this.screenToWorld(e.clientX - rect.left, e.clientY - rect.top);\n const edge = this.findEdgeAt(worldPos.x, worldPos.y);\n if (edge && this.options.onEdgeClick) {\n this.options.onEdgeClick(edge.data);\n }\n }\n\n this.isDragging = false;\n this.isPanning = false;\n this.draggedNode = null;\n this.canvas.style.cursor = this.hoveredNode ? 'pointer' : 'grab';\n });\n\n // Mouse leave\n this.canvas.addEventListener('mouseleave', () => {\n this.isDragging = false;\n this.isPanning = false;\n this.draggedNode = null;\n this.hoveredNode = null;\n this.canvas.style.cursor = 'grab';\n });\n }\n\n private screenToWorld(screenX: number, screenY: number): { x: number; y: number } {\n return {\n x: (screenX - this.transform.x) / this.transform.scale,\n y: (screenY - this.transform.y) / this.transform.scale\n };\n }\n\n private findNodeAt(x: number, y: number): Node2D | null {\n for (const node of this.nodes.values()) {\n const dx = node.x - x;\n const dy = node.y - y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < node.radius) {\n return node;\n }\n }\n return null;\n }\n\n private findEdgeAt(x: number, y: number): Edge2D | null {\n const threshold = 12; // Increased distance threshold for easier click detection\n\n for (const edge of this.edges) {\n const source = this.nodes.get(edge.source);\n const target = this.nodes.get(edge.target);\n if (!source || !target) continue;\n\n // Calculate distance from point to line segment\n const dx = target.x - source.x;\n const dy = target.y - source.y;\n const lengthSq = dx * dx + dy * dy;\n\n if (lengthSq === 0) continue;\n\n // Calculate projection of point onto line\n const t = Math.max(0, Math.min(1, ((x - source.x) * dx + (y - source.y) * dy) / lengthSq));\n const projX = source.x + t * dx;\n const projY = source.y + t * dy;\n\n // Distance from point to projection\n const distX = x - projX;\n const distY = y - projY;\n const dist = Math.sqrt(distX * distX + distY * distY);\n\n if (dist < threshold) {\n return edge;\n }\n }\n return null;\n }\n\n private startAnimation(): void {\n const animate = () => {\n if (this.isSimulating) {\n this.simulate();\n }\n this.render();\n this.animationId = requestAnimationFrame(animate);\n };\n animate();\n }\n\n private simulate(): void {\n const nodes = Array.from(this.nodes.values());\n const n = nodes.length;\n if (n === 0) return;\n\n const minDistance = 60; // Minimum distance between nodes\n const maxVelocity = 5; // Cap velocity to prevent runaway\n let totalEnergy = 0;\n\n // Repulsion between all nodes\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n const nodeA = nodes[i];\n const nodeB = nodes[j];\n let dx = nodeB.x - nodeA.x;\n let dy = nodeB.y - nodeA.y;\n let dist = Math.sqrt(dx * dx + dy * dy);\n\n // Only apply repulsion if nodes are closer than minimum distance\n if (dist < minDistance * 3) {\n if (dist < 1) dist = 1;\n\n // Stronger repulsion at very close range, falls off quickly\n const force = this.options.repulsionStrength / (dist * dist);\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n\n nodeA.vx -= fx;\n nodeA.vy -= fy;\n nodeB.vx += fx;\n nodeB.vy += fy;\n }\n }\n }\n\n // Attraction along edges - target distance based on node radius\n const targetDist = 80; // Ideal edge length\n for (const edge of this.edges) {\n const source = this.nodes.get(edge.source);\n const target = this.nodes.get(edge.target);\n if (!source || !target) continue;\n\n let dx = target.x - source.x;\n let dy = target.y - source.y;\n let dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < 1) dist = 1;\n\n // Spring-like attraction: pull if too far, push if too close\n const displacement = dist - targetDist;\n const force = displacement * this.options.attractionStrength;\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n\n source.vx += fx;\n source.vy += fy;\n target.vx -= fx;\n target.vy -= fy;\n }\n\n // Apply velocity with damping and calculate total energy\n for (const node of nodes) {\n if (this.draggedNode === node) continue;\n\n // Apply damping\n node.vx *= this.options.damping;\n node.vy *= this.options.damping;\n\n // Cap velocity\n const speed = Math.sqrt(node.vx * node.vx + node.vy * node.vy);\n if (speed > maxVelocity) {\n node.vx = (node.vx / speed) * maxVelocity;\n node.vy = (node.vy / speed) * maxVelocity;\n }\n\n // Update position\n node.x += node.vx;\n node.y += node.vy;\n\n // Track total kinetic energy\n totalEnergy += node.vx * node.vx + node.vy * node.vy;\n }\n\n // Auto-stop simulation when energy is very low (system at rest)\n if (totalEnergy < 0.01 && !this.draggedNode) {\n this.isSimulating = false;\n }\n }\n\n private render(): void {\n const ctx = this.ctx;\n const width = this.canvas.width / (window.devicePixelRatio || 1);\n const height = this.canvas.height / (window.devicePixelRatio || 1);\n\n // Clear canvas\n ctx.fillStyle = this.options.backgroundColor;\n ctx.fillRect(0, 0, width, height);\n\n // Draw grid\n this.renderGrid(width, height);\n\n // Apply transform\n ctx.save();\n ctx.translate(this.transform.x, this.transform.y);\n ctx.scale(this.transform.scale, this.transform.scale);\n\n // Draw edges\n this.renderEdges();\n\n // Draw nodes\n this.renderNodes();\n\n ctx.restore();\n }\n\n private renderGrid(width: number, height: number): void {\n const ctx = this.ctx;\n const gridSize = 40 * this.transform.scale;\n const dotRadius = 1.5;\n\n // Calculate grid offset based on transform\n const offsetX = this.transform.x % gridSize;\n const offsetY = this.transform.y % gridSize;\n\n ctx.fillStyle = this.options.gridColor;\n\n for (let x = offsetX; x < width; x += gridSize) {\n for (let y = offsetY; y < height; y += gridSize) {\n ctx.beginPath();\n ctx.arc(x, y, dotRadius, 0, Math.PI * 2);\n ctx.fill();\n }\n }\n }\n\n private renderEdges(): void {\n const ctx = this.ctx;\n\n for (const edge of this.edges) {\n const source = this.nodes.get(edge.source);\n const target = this.nodes.get(edge.target);\n if (!source || !target) continue;\n\n const isHovered = edge === this.hoveredEdge;\n\n // Draw edge line with gradient\n const gradient = ctx.createLinearGradient(source.x, source.y, target.x, target.y);\n\n if (isHovered) {\n gradient.addColorStop(0, 'rgba(255, 153, 102, 0.8)');\n gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');\n gradient.addColorStop(1, 'rgba(102, 153, 255, 0.8)');\n ctx.lineWidth = 3.0;\n } else {\n gradient.addColorStop(0, 'rgba(255, 153, 102, 0.3)');\n gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.15)');\n gradient.addColorStop(1, 'rgba(102, 153, 255, 0.3)');\n ctx.lineWidth = 1.5;\n }\n\n ctx.beginPath();\n ctx.moveTo(source.x, source.y);\n ctx.lineTo(target.x, target.y);\n ctx.strokeStyle = gradient;\n ctx.stroke();\n }\n }\n\n private renderNodes(): void {\n const ctx = this.ctx;\n\n for (const node of this.nodes.values()) {\n const isHovered = node === this.hoveredNode;\n const isSelected = node === this.selectedNode;\n const isConnectedToHoveredEdge = this.hoveredEdge &&\n (node.data.id === this.hoveredEdge.source || node.data.id === this.hoveredEdge.target);\n\n const radius = node.radius * (isHovered ? 1.1 : 1);\n\n // Outer glow\n if (isHovered || isSelected || isConnectedToHoveredEdge) {\n const glowGradient = ctx.createRadialGradient(\n node.x, node.y, radius * 0.5,\n node.x, node.y, radius * 2\n );\n\n const alpha = (isHovered || isSelected) ? 0.4 : 0.25;\n glowGradient.addColorStop(0, `rgba(255, 153, 102, ${alpha})`);\n glowGradient.addColorStop(1, 'rgba(255, 153, 102, 0)');\n\n ctx.fillStyle = glowGradient;\n ctx.beginPath();\n ctx.arc(node.x, node.y, radius * 2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // Node background with gradient\n const nodeGradient = ctx.createRadialGradient(\n node.x - radius * 0.3, node.y - radius * 0.3, 0,\n node.x, node.y, radius\n );\n\n // Convert hex color to RGB\n const r = (node.color >> 16) & 255;\n const g = (node.color >> 8) & 255;\n const b = node.color & 255;\n\n nodeGradient.addColorStop(0, `rgba(${Math.min(255, r + 60)}, ${Math.min(255, g + 60)}, ${Math.min(255, b + 60)}, 0.95)`);\n nodeGradient.addColorStop(0.7, `rgba(${r}, ${g}, ${b}, 0.9)`);\n nodeGradient.addColorStop(1, `rgba(${Math.max(0, r - 40)}, ${Math.max(0, g - 40)}, ${Math.max(0, b - 40)}, 0.85)`);\n\n // Draw node circle\n ctx.beginPath();\n ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);\n ctx.fillStyle = nodeGradient;\n ctx.fill();\n\n // Subtle border\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';\n ctx.lineWidth = 1;\n ctx.stroke();\n\n // Inner highlight\n ctx.beginPath();\n ctx.arc(node.x - radius * 0.25, node.y - radius * 0.25, radius * 0.3, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.fill();\n\n // Draw label\n ctx.fillStyle = 'white';\n ctx.font = '600 11px Inter, -apple-system, BlinkMacSystemFont, sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Truncate label if too long\n const maxWidth = radius * 1.6;\n let label = node.label;\n let textWidth = ctx.measureText(label).width;\n if (textWidth > maxWidth) {\n while (textWidth > maxWidth && label.length > 3) {\n label = label.slice(0, -1);\n textWidth = ctx.measureText(label + '...').width;\n }\n label += '...';\n }\n\n // Text shadow for better readability\n ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';\n ctx.shadowBlur = 3;\n ctx.fillText(label, node.x, node.y);\n ctx.shadowBlur = 0;\n }\n }\n\n /**\n * Sets the graph data\n */\n public setData(data: { nodes: NodeData[]; edges: Edge[] }): void {\n this.nodes.clear();\n this.edges = [];\n this.nodeIdToIndex.clear();\n\n // Create nodes with positions\n data.nodes.forEach((nodeData, index) => {\n const pos = nodeData.position || {\n x: (Math.random() - 0.5) * 300,\n y: (Math.random() - 0.5) * 300\n };\n\n const node: Node2D = {\n id: nodeData.id,\n label: nodeData.label,\n x: pos.x,\n y: pos.y,\n vx: 0,\n vy: 0,\n color: nodeData.color || 0xff9966, // Match 3D tangerine color\n radius: this.options.nodeRadius,\n data: nodeData\n };\n\n this.nodes.set(nodeData.id, node);\n this.nodeIdToIndex.set(nodeData.id, index);\n });\n\n // Create edges\n this.edges = data.edges.map(edge => ({\n source: edge.source,\n target: edge.target,\n relationship: edge.relationship,\n data: edge\n }));\n }\n\n /**\n * Adds a node\n */\n public addNode(nodeData: NodeData): void {\n const pos = nodeData.position || {\n x: (Math.random() - 0.5) * 300,\n y: (Math.random() - 0.5) * 300\n };\n\n const node: Node2D = {\n id: nodeData.id,\n label: nodeData.label,\n x: pos.x,\n y: pos.y,\n vx: 0,\n vy: 0,\n color: nodeData.color || 0xff9966, // Match 3D tangerine color\n radius: this.options.nodeRadius,\n data: nodeData\n };\n\n this.nodes.set(nodeData.id, node);\n }\n\n /**\n * Adds an edge\n */\n public addEdge(edge: Edge): void {\n this.edges.push({\n source: edge.source,\n target: edge.target,\n relationship: edge.relationship,\n data: edge\n });\n }\n\n /**\n * Removes a node\n */\n public removeNode(nodeId: string): void {\n this.nodes.delete(nodeId);\n this.edges = this.edges.filter(e => e.source !== nodeId && e.target !== nodeId);\n }\n\n /**\n * Gets a node by ID\n */\n public getNode(nodeId: string): Node2D | undefined {\n return this.nodes.get(nodeId);\n }\n\n /**\n * Gets all nodes\n */\n public getAllNodes(): NodeData[] {\n return Array.from(this.nodes.values()).map(n => n.data);\n }\n\n /**\n * Gets node count\n */\n public getNodeCount(): number {\n return this.nodes.size;\n }\n\n /**\n * Gets edge count\n */\n public getEdgeCount(): number {\n return this.edges.length;\n }\n\n /**\n * Focuses on a node\n */\n public focusOnNode(nodeId: string): void {\n const node = this.nodes.get(nodeId);\n if (!node) return;\n\n const targetX = this.canvas.width / 2 / (window.devicePixelRatio || 1) - node.x * this.transform.scale;\n const targetY = this.canvas.height / 2 / (window.devicePixelRatio || 1) - node.y * this.transform.scale;\n\n // Animate to position\n const startX = this.transform.x;\n const startY = this.transform.y;\n const duration = 500;\n const startTime = performance.now();\n\n const animate = () => {\n const elapsed = performance.now() - startTime;\n const progress = Math.min(elapsed / duration, 1);\n const eased = 1 - Math.pow(1 - progress, 3);\n\n this.transform.x = startX + (targetX - startX) * eased;\n this.transform.y = startY + (targetY - startY) * eased;\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n } else {\n this.selectedNode = node;\n }\n };\n\n animate();\n }\n\n /**\n * Updates node positions from 3D data\n */\n public syncFrom3D(nodesMap: Map<string, InternalNode>): void {\n nodesMap.forEach((node3d, id) => {\n const node2d = this.nodes.get(id);\n if (node2d) {\n // Use x and y from 3D, scale up for better spacing in 2D\n node2d.x = node3d.position.x * 3; // Scale for visibility\n node2d.y = node3d.position.y * 3;\n node2d.vx = 0;\n node2d.vy = 0;\n }\n });\n // Positions from 3D are already stable, so stop simulation\n this.isSimulating = false;\n }\n\n /**\n * Gets 2D positions for syncing to 3D\n */\n public getPositions(): Map<string, { x: number; y: number }> {\n const positions = new Map<string, { x: number; y: number }>();\n this.nodes.forEach((node, id) => {\n positions.set(id, { x: node.x, y: node.y });\n });\n return positions;\n }\n\n /**\n * Show/hide the canvas\n */\n public show(): void {\n this.canvas.style.display = 'block';\n }\n\n public hide(): void {\n this.canvas.style.display = 'none';\n }\n\n /**\n * Updates physics parameters in real-time\n */\n public setPhysicsParams(params: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number\n }): void {\n if (params.repulsionStrength !== undefined) {\n this.options.repulsionStrength = params.repulsionStrength;\n }\n if (params.attractionStrength !== undefined) {\n this.options.attractionStrength = params.attractionStrength;\n }\n if (params.damping !== undefined) {\n this.options.damping = params.damping;\n }\n // Restart simulation to apply new params\n this.isSimulating = true;\n }\n\n /**\n * Dispose resources\n */\n public dispose(): void {\n if (this.animationId) {\n cancelAnimationFrame(this.animationId);\n }\n window.removeEventListener('resize', this.resizeHandler);\n if (this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n }\n}\n","import type {\n ForceGraph3DOptions,\n GraphData,\n NodeData,\n Edge,\n InternalNode,\n EventType,\n EventCallback\n} from './utils/types';\nimport { DEFAULT_OPTIONS } from './utils/types';\nimport { validateContainer } from './utils/ContainerManager';\nimport { validateNodeData, validateEdgeData, validateNodeId } from './utils/validation';\n\n// Core components\nimport { SceneManager } from './core/SceneManager';\nimport { NodeManager } from './core/NodeManager';\nimport { EdgeManager } from './core/EdgeManager';\nimport { GraphEngine } from './core/GraphEngine';\nimport { RendererManager } from './core/RendererManager';\n\n// Factories\nimport { MaterialFactory } from './factory/MaterialFactory';\nimport { NodeFactory } from './factory/NodeFactory';\nimport { EdgeFactory } from './factory/EdgeFactory';\n\n// Performance\nimport { LODManager } from './performance/LODManager';\nimport { FrustumCuller } from './performance/FrustumCuller';\n\n// Interaction\nimport { RaycasterManager } from './interaction/RaycasterManager';\nimport type { EdgeHoverInfo } from './interaction/RaycasterManager';\nimport { PanelManager } from './interaction/PanelManager';\nimport { EdgePanelManager } from './interaction/EdgePanelManager';\nimport { EdgeTooltipManager } from './interaction/EdgeTooltipManager';\nimport { SearchManager } from './interaction/SearchManager';\nimport { ViewToggleManager, type ViewMode } from './interaction/ViewToggleManager';\n\n// 2D Renderer\nimport { ForceGraph2D } from './core/ForceGraph2D';\n\ndeclare const __DEV__: boolean;\n\n/**\n * ForceGraph3D\n * Main class for the 3D force-directed graph library\n */\nexport class ForceGraph3D {\n // Options\n private options: ForceGraph3DOptions;\n private container: HTMLElement;\n\n // Core components\n private sceneManager: SceneManager;\n private nodeManager: NodeManager;\n private edgeManager: EdgeManager;\n private graphEngine: GraphEngine;\n private rendererManager: RendererManager;\n\n // Factories\n private materialFactory: MaterialFactory;\n private nodeFactory: NodeFactory;\n private edgeFactory: EdgeFactory;\n\n // Performance\n private lodManager: LODManager;\n private frustumCuller: FrustumCuller;\n\n // Interaction\n private raycasterManager: RaycasterManager;\n private panelManager: PanelManager;\n private edgePanelManager: EdgePanelManager;\n private edgeTooltipManager: EdgeTooltipManager;\n private searchManager: SearchManager | null = null;\n private viewToggleManager: ViewToggleManager | null = null;\n\n // 2D Renderer\n private forceGraph2D: ForceGraph2D | null = null;\n\n // Event system\n private eventCallbacks: Map<EventType, EventCallback[]> = new Map();\n\n // State\n private initialized: boolean = false;\n private devControls: HTMLElement | null = null;\n private viewMode: ViewMode = '3d';\n private graphData: GraphData | null = null; // Store graph data for view switching\n\n constructor(container?: HTMLElement | null, options: ForceGraph3DOptions = {}) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.container = validateContainer(container);\n\n // Initialize factories\n this.materialFactory = new MaterialFactory();\n this.nodeFactory = new NodeFactory(\n this.materialFactory,\n this.options.nodeRadius ?? DEFAULT_OPTIONS.nodeRadius,\n this.options.lodSegments ?? DEFAULT_OPTIONS.lodSegments,\n this.options.defaultNodeColor ?? DEFAULT_OPTIONS.defaultNodeColor\n );\n this.edgeFactory = new EdgeFactory(\n this.materialFactory,\n this.options.edgeColor ?? DEFAULT_OPTIONS.edgeColor,\n this.options.edgeOpacity ?? DEFAULT_OPTIONS.edgeOpacity\n );\n\n // Initialize scene\n this.sceneManager = new SceneManager(this.container, this.options);\n\n // Initialize performance managers\n this.lodManager = new LODManager(\n this.sceneManager.camera,\n this.options.lodDistances ?? DEFAULT_OPTIONS.lodDistances,\n this.options.enableLOD ?? DEFAULT_OPTIONS.enableLOD\n );\n this.frustumCuller = new FrustumCuller(\n this.sceneManager.camera,\n this.options.enableEdgeCulling ?? DEFAULT_OPTIONS.enableEdgeCulling\n );\n\n // Initialize node/edge managers\n this.nodeManager = new NodeManager(this.sceneManager, this.nodeFactory);\n this.edgeManager = new EdgeManager(this.sceneManager, this.nodeManager, this.edgeFactory);\n\n // Initialize graph engine\n this.graphEngine = new GraphEngine(\n this.nodeManager.getAllNodes(),\n this.edgeManager.getAllEdges(),\n {\n repulsionStrength: this.options.repulsionStrength,\n attractionStrength: this.options.attractionStrength,\n damping: this.options.damping,\n useBarnesHut: this.options.useBarnesHut,\n barnesHutTheta: this.options.barnesHutTheta,\n }\n );\n\n // Initialize renderer\n this.rendererManager = new RendererManager(\n this.sceneManager,\n () => this.onSimulate(),\n () => this.onRender(),\n this.options.targetFPS ?? DEFAULT_OPTIONS.targetFPS\n );\n\n // Initialize interaction\n this.raycasterManager = new RaycasterManager(this.sceneManager, this.container);\n this.panelManager = new PanelManager(this.container);\n this.edgePanelManager = new EdgePanelManager(this.container);\n this.edgeTooltipManager = new EdgeTooltipManager();\n\n // Set up edge panel node click callback for navigation\n this.edgePanelManager.setNodeClickCallback((nodeId: string) => {\n this.edgePanelManager.hide();\n this.focusOnNode(nodeId);\n setTimeout(() => {\n this.showNodePanel(nodeId);\n }, 400);\n });\n\n // Initialize search\n if (this.options.showSearch !== false) {\n this.searchManager = new SearchManager(this.container, {\n placeholder: this.options.searchPlaceholder,\n onSearch: (query: string) => ({\n nodeResults: this.searchNodes(query),\n edgeResults: this.searchEdges(query)\n }),\n onResultClick: (nodeId: string) => {\n this.focusOnNode(nodeId);\n setTimeout(() => {\n this.showNodePanel(nodeId);\n }, 400);\n }\n });\n }\n\n // Initialize view toggle\n if (this.options.showViewToggle !== false) {\n this.viewMode = (this.options.initialViewMode as ViewMode) || '3d';\n this.viewToggleManager = new ViewToggleManager(this.container, {\n initialMode: this.viewMode,\n onViewChange: (mode: ViewMode) => {\n this.switchView(mode);\n }\n });\n }\n\n // Setup callbacks\n this.setupCallbacks();\n\n // Dev mode controls\n if (typeof __DEV__ !== 'undefined' && __DEV__) {\n this.createDevControls();\n }\n\n // Start rendering\n this.rendererManager.start();\n this.initialized = true;\n\n // Emit ready event\n this.emit('ready');\n }\n\n /**\n * Sets up internal callbacks\n */\n private setupCallbacks(): void {\n // Node click callback\n this.raycasterManager.setClickCallback((nodeData) => {\n this.onNodeClick(nodeData);\n });\n\n // Node hover callback\n if (this.options.onNodeHover) {\n this.raycasterManager.setHoverCallback(this.options.onNodeHover);\n }\n\n // Panel expand callback\n this.panelManager.setExpandCallback((nodeId, depth) => {\n this.expandNode(nodeId, depth);\n });\n\n // Custom panel template\n if (this.options.panelTemplate) {\n this.panelManager.setPanelTemplate(this.options.panelTemplate);\n }\n\n // Custom panel styles\n if (this.options.panelStyles) {\n this.panelManager.setPanelStyles(this.options.panelStyles);\n }\n\n // Edge hover callback\n this.raycasterManager.setEdgeHoverCallback((info: EdgeHoverInfo | null) => {\n this.onEdgeHover(info);\n });\n\n // Edge click callback\n this.raycasterManager.setEdgeClickCallback((info: EdgeHoverInfo) => {\n this.onEdgeClick(info);\n });\n }\n\n /**\n * Handles edge hover\n */\n private onEdgeHover(info: EdgeHoverInfo | null): void {\n if (info) {\n // Highlight the edge\n this.edgeManager.highlightEdge(info.edge.source, info.edge.target);\n\n // Show tooltip\n const rect = this.container.getBoundingClientRect();\n const mouseX = rect.left + rect.width / 2;\n const mouseY = rect.top + rect.height / 2;\n this.edgeTooltipManager.show(info.edge, info.sourceNode, info.targetNode, mouseX, mouseY);\n\n // Call user callback\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(info.edge, info.sourceNode, info.targetNode);\n }\n this.emit('edgeHover', info.edge, info.sourceNode, info.targetNode);\n } else {\n // Unhighlight\n this.edgeManager.unhighlightCurrentEdge();\n this.edgeTooltipManager.hide();\n\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(null, null, null);\n }\n this.emit('edgeHover', null, null, null);\n }\n }\n\n /**\n * Handles node click\n */\n private onNodeClick(nodeData: NodeData): void {\n // Hide edge panel if visible\n this.edgePanelManager.hide();\n\n // Get neighbors\n const neighborIds = this.edgeManager.getNeighborIds(nodeData.id);\n const neighbors: NodeData[] = neighborIds\n .map(id => this.nodeManager.getNode(id))\n .filter((n): n is InternalNode => n !== undefined);\n\n // Show panel\n if (this.options.showPanel !== false) {\n this.panelManager.show(nodeData, neighbors);\n }\n\n // Call user callback\n if (this.options.onNodeClick) {\n this.options.onNodeClick(nodeData);\n }\n\n this.emit('nodeClick', nodeData);\n }\n\n /**\n * Handles edge click\n */\n private onEdgeClick(info: EdgeHoverInfo): void {\n // Hide node panel if visible\n this.panelManager.hide();\n\n // Hide tooltip\n this.edgeTooltipManager.hide();\n\n // Highlight the edge\n this.edgeManager.highlightEdge(info.edge.source, info.edge.target);\n\n // Show edge panel with relationship info\n this.edgePanelManager.show(info.edge, info.sourceNode, info.targetNode);\n\n // Focus camera on both nodes\n this.focusOnEdge(info.edge.source, info.edge.target);\n\n // Emit event\n this.emit('edgeClick', info.edge, info.sourceNode, info.targetNode);\n }\n\n /**\n * Called every simulation step\n */\n private onSimulate(): void {\n // Run physics simulation\n this.graphEngine.simulate();\n\n // Update node positions in the scene\n for (const [nodeId, node] of this.nodeManager.getAllNodes()) {\n this.nodeManager.updateNodePosition(nodeId, node.position);\n\n // Update LOD based on distance from camera\n if (this.options.enableLOD) {\n const newLodLevel = this.lodManager.getLODLevel(node.position);\n this.nodeManager.updateNodeLOD(nodeId, newLodLevel);\n }\n }\n\n // Update edge positions\n this.edgeManager.updateEdgePositions();\n }\n\n /**\n * Called every render frame\n */\n private onRender(): void {\n // Update frustum culler\n this.frustumCuller.update();\n\n // Update raycaster with current node and edge objects\n this.raycasterManager.setNodeObjects(this.nodeManager.getAllNodeObjects());\n this.raycasterManager.setEdgeObjects(this.edgeManager.getAllEdgeLines());\n }\n\n // ==========================================================================\n // Public API\n // ==========================================================================\n\n /**\n * Sets the graph data\n */\n setData(data: GraphData): void {\n // Store data for view switching\n this.graphData = data;\n\n // Clear existing data\n this.edgeManager.clear();\n this.nodeManager.clear();\n\n // Add nodes\n if (data.nodes && Array.isArray(data.nodes)) {\n for (const nodeData of data.nodes) {\n this.addNode(nodeData);\n }\n }\n\n // Add edges\n if (data.edges && Array.isArray(data.edges)) {\n for (const edgeData of data.edges) {\n this.addEdge(edgeData);\n }\n }\n\n // Update graph engine references\n this.graphEngine = new GraphEngine(\n this.nodeManager.getAllNodes(),\n this.edgeManager.getAllEdges(),\n {\n repulsionStrength: this.options.repulsionStrength,\n attractionStrength: this.options.attractionStrength,\n damping: this.options.damping,\n useBarnesHut: this.options.useBarnesHut,\n barnesHutTheta: this.options.barnesHutTheta,\n }\n );\n\n // Restart simulation\n this.graphEngine.restart();\n\n // Sync to 2D view if active\n if (this.forceGraph2D) {\n this.forceGraph2D.setData(data);\n }\n }\n\n /**\n * Adds a node to the graph\n * @returns true if added, false if node already exists or invalid\n */\n addNode(nodeData: NodeData): boolean {\n if (!validateNodeData(nodeData)) {\n return false;\n }\n\n const success = this.nodeManager.addNode(nodeData);\n\n if (success) {\n this.graphEngine.restart();\n\n // Also add to 2D view if it exists\n if (this.forceGraph2D) {\n this.forceGraph2D.addNode(nodeData);\n }\n\n if (this.options.onNodeAdd) {\n this.options.onNodeAdd(nodeData);\n }\n this.emit('nodeAdd', nodeData);\n }\n\n return success;\n }\n\n /**\n * Removes a node from the graph\n * @returns true if removed, false if not found\n */\n removeNode(nodeId: string): boolean {\n if (!validateNodeId(nodeId)) {\n return false;\n }\n\n // First remove all connected edges\n this.edgeManager.removeEdgesForNode(nodeId);\n\n // Then remove the node\n const success = this.nodeManager.removeNode(nodeId);\n\n if (success) {\n this.graphEngine.restart();\n\n if (this.options.onNodeRemove) {\n this.options.onNodeRemove(nodeId);\n }\n this.emit('nodeRemove', nodeId);\n\n // Hide panel if it's showing this node\n if (this.panelManager.getCurrentNodeId() === nodeId) {\n this.panelManager.hide();\n }\n }\n\n return success;\n }\n\n /**\n * Updates a node's properties\n */\n updateNode(nodeId: string, updates: Partial<NodeData>): boolean {\n return this.nodeManager.updateNode(nodeId, updates);\n }\n\n /**\n * Adds an edge to the graph\n * @returns true if added, false if edge already exists or nodes don't exist\n */\n addEdge(edge: Edge): boolean {\n if (!validateEdgeData(edge)) {\n return false;\n }\n\n const success = this.edgeManager.addEdge(edge);\n\n if (success) {\n // Update graph engine edges\n this.graphEngine.setEdges(this.edgeManager.getAllEdges());\n this.graphEngine.restart();\n\n // Also add to 2D view if it exists\n if (this.forceGraph2D) {\n this.forceGraph2D.addEdge(edge);\n }\n\n if (this.options.onEdgeAdd) {\n this.options.onEdgeAdd(edge);\n }\n this.emit('edgeAdd', edge);\n }\n\n return success;\n }\n\n /**\n * Removes an edge from the graph\n * @returns true if removed, false if not found\n */\n removeEdge(source: string, target: string): boolean {\n const success = this.edgeManager.removeEdge(source, target);\n\n if (success) {\n // Update graph engine edges\n this.graphEngine.setEdges(this.edgeManager.getAllEdges());\n\n if (this.options.onEdgeRemove) {\n this.options.onEdgeRemove({ source, target });\n }\n this.emit('edgeRemove', { source, target });\n }\n\n return success;\n }\n\n /**\n * Expands a node by fetching more data\n * @param nodeId - The ID of the node to expand\n * @param depth - The depth of expansion (1-3 levels, default 1)\n * @param fetchFn - Optional fetch function to override the default\n */\n async expandNode(nodeId: string, depth: number = 1, fetchFn?: (nodeId: string, depth: number) => Promise<GraphData>): Promise<boolean> {\n const expandCallback = fetchFn ?? this.options.onExpand;\n\n if (!expandCallback) {\n console.warn('[ForceGraph3D] No expand callback provided');\n return false;\n }\n\n try {\n const newData = await expandCallback(nodeId, depth);\n\n if (newData.nodes && Array.isArray(newData.nodes)) {\n for (const nodeData of newData.nodes) {\n this.addNode(nodeData);\n }\n }\n\n if (newData.edges && Array.isArray(newData.edges)) {\n for (const edgeData of newData.edges) {\n this.addEdge(edgeData);\n }\n }\n\n // Hide panel after expand\n this.panelManager.hide();\n\n this.emit('expand', nodeId, newData);\n return true;\n } catch (error) {\n console.error('[ForceGraph3D] Error expanding node:', error);\n return false;\n }\n }\n\n /**\n * Gets a node by ID\n */\n getNode(nodeId: string): NodeData | undefined {\n return this.nodeManager.getNode(nodeId);\n }\n\n /**\n * Gets neighbor nodes for a node\n */\n getNeighbors(nodeId: string): NodeData[] {\n const neighborIds = this.edgeManager.getNeighborIds(nodeId);\n return neighborIds\n .map(id => this.nodeManager.getNode(id))\n .filter((n): n is InternalNode => n !== undefined);\n }\n\n /**\n * Gets the number of nodes\n */\n getNodeCount(): number {\n return this.nodeManager.getNodeCount();\n }\n\n /**\n * Gets the number of edges\n */\n getEdgeCount(): number {\n return this.edgeManager.getEdgeCount();\n }\n\n /**\n * Sets the expand callback\n * @param callback - Function that fetches expansion data given a nodeId and depth\n */\n setExpandCallback(callback: (nodeId: string, depth?: number) => Promise<GraphData>): void {\n this.options.onExpand = callback;\n }\n\n /**\n * Focuses the camera on a specific node with smooth animation\n */\n focusOnNode(nodeId: string, distance: number = 30): void {\n // Handle 2D view\n if (this.viewMode === '2d' && this.forceGraph2D) {\n this.forceGraph2D.focusOnNode(nodeId);\n return;\n }\n\n const node = this.nodeManager.getNode(nodeId);\n if (!node) {\n console.warn(`[ForceGraph3D] Node \"${nodeId}\" not found`);\n return;\n }\n\n const targetPos = node.position;\n const camera = this.sceneManager.camera;\n const controls = this.sceneManager.controls;\n\n // Calculate target camera position (offset from node)\n const direction = camera.position.clone().sub(controls.target).normalize();\n const newCameraPos = {\n x: targetPos.x + direction.x * distance,\n y: targetPos.y + direction.y * distance,\n z: targetPos.z + direction.z * distance,\n };\n\n // Animate camera and controls target\n const startCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z };\n const startTarget = { x: controls.target.x, y: controls.target.y, z: controls.target.z };\n const duration = 800;\n const startTime = performance.now();\n\n const animate = () => {\n const elapsed = performance.now() - startTime;\n const progress = Math.min(elapsed / duration, 1);\n\n // Ease out cubic\n const eased = 1 - Math.pow(1 - progress, 3);\n\n // Interpolate camera position\n camera.position.x = startCameraPos.x + (newCameraPos.x - startCameraPos.x) * eased;\n camera.position.y = startCameraPos.y + (newCameraPos.y - startCameraPos.y) * eased;\n camera.position.z = startCameraPos.z + (newCameraPos.z - startCameraPos.z) * eased;\n\n // Interpolate controls target\n controls.target.x = startTarget.x + (targetPos.x - startTarget.x) * eased;\n controls.target.y = startTarget.y + (targetPos.y - startTarget.y) * eased;\n controls.target.z = startTarget.z + (targetPos.z - startTarget.z) * eased;\n\n controls.update();\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n }\n };\n\n animate();\n }\n\n /**\n * Focuses the camera on an edge (both source and target nodes) with smooth animation\n * Camera targets the midpoint and zooms out enough to see both nodes\n */\n focusOnEdge(sourceId: string, targetId: string, padding: number = 1.5): void {\n const sourceNode = this.nodeManager.getNode(sourceId);\n const targetNode = this.nodeManager.getNode(targetId);\n\n if (!sourceNode || !targetNode) {\n console.warn(`[ForceGraph3D] Could not find nodes for edge \"${sourceId}\" -> \"${targetId}\"`);\n return;\n }\n\n const camera = this.sceneManager.camera;\n const controls = this.sceneManager.controls;\n\n // Calculate midpoint between the two nodes\n const midpoint = {\n x: (sourceNode.position.x + targetNode.position.x) / 2,\n y: (sourceNode.position.y + targetNode.position.y) / 2,\n z: (sourceNode.position.z + targetNode.position.z) / 2,\n };\n\n // Calculate distance between nodes\n const dx = targetNode.position.x - sourceNode.position.x;\n const dy = targetNode.position.y - sourceNode.position.y;\n const dz = targetNode.position.z - sourceNode.position.z;\n const nodeDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n // Calculate camera distance (far enough to see both nodes with padding)\n // Use the node distance with padding factor, minimum of 40\n const cameraDistance = Math.max(nodeDistance * padding, 40);\n\n // Calculate target camera position (offset from midpoint in camera's current direction)\n const direction = camera.position.clone().sub(controls.target).normalize();\n const newCameraPos = {\n x: midpoint.x + direction.x * cameraDistance,\n y: midpoint.y + direction.y * cameraDistance,\n z: midpoint.z + direction.z * cameraDistance,\n };\n\n // Animate camera and controls target\n const startCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z };\n const startTarget = { x: controls.target.x, y: controls.target.y, z: controls.target.z };\n const duration = 800;\n const startTime = performance.now();\n\n const animate = () => {\n const elapsed = performance.now() - startTime;\n const progress = Math.min(elapsed / duration, 1);\n\n // Ease out cubic\n const eased = 1 - Math.pow(1 - progress, 3);\n\n // Interpolate camera position\n camera.position.x = startCameraPos.x + (newCameraPos.x - startCameraPos.x) * eased;\n camera.position.y = startCameraPos.y + (newCameraPos.y - startCameraPos.y) * eased;\n camera.position.z = startCameraPos.z + (newCameraPos.z - startCameraPos.z) * eased;\n\n // Interpolate controls target to midpoint\n controls.target.x = startTarget.x + (midpoint.x - startTarget.x) * eased;\n controls.target.y = startTarget.y + (midpoint.y - startTarget.y) * eased;\n controls.target.z = startTarget.z + (midpoint.z - startTarget.z) * eased;\n\n controls.update();\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n }\n };\n\n animate();\n }\n\n /**\n * Shows the info panel for a specific node\n */\n showNodePanel(nodeId: string): void {\n const node = this.nodeManager.getNode(nodeId);\n if (!node) {\n console.warn(`[ForceGraph3D] Node \"${nodeId}\" not found`);\n return;\n }\n\n const neighbors = this.getNeighbors(nodeId);\n this.panelManager.show(node, neighbors);\n }\n\n /**\n * Searches nodes by label or ID (case-insensitive)\n * @returns Array of matching nodes\n */\n searchNodes(query: string): NodeData[] {\n if (!query || query.trim() === '') {\n return [];\n }\n\n const lowerQuery = query.toLowerCase().trim();\n const nodesMap = this.nodeManager.getAllNodes();\n const results: NodeData[] = [];\n\n nodesMap.forEach((node) => {\n const labelMatch = node.label?.toLowerCase().includes(lowerQuery);\n const idMatch = node.id?.toLowerCase().includes(lowerQuery);\n const typeMatch = (node as any).type?.toLowerCase().includes(lowerQuery);\n if (labelMatch || idMatch || typeMatch) {\n results.push(node);\n }\n });\n\n return results;\n }\n\n /**\n * Searches edges by relationship (case-insensitive)\n * @returns Array of matching edges with source/target node info\n */\n searchEdges(query: string): Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> {\n if (!query || query.trim() === '') {\n return [];\n }\n\n const lowerQuery = query.toLowerCase().trim();\n const allEdges = this.edgeManager.getAllEdges();\n const results: Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> = [];\n\n for (const edge of allEdges) {\n const relationshipMatch = (edge as any).relationship?.toLowerCase().includes(lowerQuery);\n if (relationshipMatch) {\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n if (sourceNode && targetNode) {\n results.push({ edge, sourceNode, targetNode });\n }\n }\n }\n\n return results;\n }\n\n /**\n * Gets all nodes as an array\n */\n getAllNodes(): NodeData[] {\n const nodesMap = this.nodeManager.getAllNodes();\n return Array.from(nodesMap.values());\n }\n\n /**\n * Gets all edges\n */\n getAllEdges(): Edge[] {\n return this.edgeManager.getAllEdges();\n }\n\n /**\n * Checks if the graph is initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * Gets the current view mode\n */\n getViewMode(): ViewMode {\n return this.viewMode;\n }\n\n /**\n * Switches between 2D and 3D view modes\n */\n switchView(mode: ViewMode): void {\n if (this.viewMode === mode) return;\n\n this.viewMode = mode;\n\n // Hide panels when switching views\n this.panelManager.hide();\n this.edgePanelManager.hide();\n this.edgeTooltipManager.hide();\n\n if (mode === '2d') {\n // Switch to 2D mode\n // Hide 3D renderer\n this.sceneManager.renderer.domElement.style.display = 'none';\n this.rendererManager.stop();\n\n // Create 2D renderer if not exists\n if (!this.forceGraph2D) {\n this.forceGraph2D = new ForceGraph2D(this.container, {\n backgroundColor: '#0a0a0a',\n nodeRadius: 24,\n onNodeClick: (nodeData: NodeData) => {\n this.onNodeClick(nodeData);\n },\n onNodeHover: (nodeData: NodeData | null) => {\n if (this.options.onNodeHover) {\n this.options.onNodeHover(nodeData);\n }\n },\n onEdgeHover: (edge: Edge | null, event?: MouseEvent) => {\n if (edge && event) {\n // Get source and target node data for tooltip\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n if (sourceNode && targetNode) {\n this.edgeTooltipManager.show(\n edge,\n sourceNode,\n targetNode,\n event.clientX,\n event.clientY\n );\n }\n } else {\n this.edgeTooltipManager.hide();\n }\n },\n onEdgeClick: (edge: Edge) => {\n // Show edge panel when clicking a relationship\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n if (sourceNode && targetNode) {\n this.edgePanelManager.show(edge, sourceNode, targetNode);\n }\n }\n });\n\n // Load current data\n if (this.graphData) {\n this.forceGraph2D.setData(this.graphData);\n // Sync positions from 3D\n this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes());\n }\n } else {\n this.forceGraph2D.show();\n // Sync positions from 3D\n this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes());\n }\n } else {\n // Switch to 3D mode\n // Hide 2D renderer\n if (this.forceGraph2D) {\n this.forceGraph2D.hide();\n }\n\n // Show 3D renderer\n this.sceneManager.renderer.domElement.style.display = 'block';\n this.rendererManager.start();\n }\n\n // Emit view change event\n this.emit('viewChange', mode);\n }\n\n /**\n * Registers an event listener\n */\n on(event: EventType, callback: EventCallback): void {\n if (!this.eventCallbacks.has(event)) {\n this.eventCallbacks.set(event, []);\n }\n this.eventCallbacks.get(event)!.push(callback);\n }\n\n /**\n * Emits an event\n */\n private emit(event: EventType, ...args: unknown[]): void {\n const callbacks = this.eventCallbacks.get(event);\n if (callbacks) {\n callbacks.forEach(cb => cb(...args));\n }\n }\n\n /**\n * Sets physics parameters for both 3D and 2D views\n */\n setPhysicsParams(params: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n }): void {\n // Update 3D physics\n this.graphEngine.setPhysicsParams(params);\n this.graphEngine.restart();\n\n // Update 2D physics if available\n if (this.forceGraph2D) {\n this.forceGraph2D.setPhysicsParams(params);\n }\n }\n\n /**\n * Creates dev mode controls (only in development)\n */\n private createDevControls(): void {\n this.devControls = document.createElement('div');\n this.devControls.className = 'force-graph-dev-controls';\n this.devControls.innerHTML = `\n <style>\n .force-graph-dev-controls {\n position: absolute;\n top: 20px;\n right: 20px;\n background: rgba(0, 0, 0, 0.8);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n padding: 16px;\n color: white;\n font-family: 'Inter', -apple-system, sans-serif;\n font-size: 12px;\n z-index: 1001;\n min-width: 220px;\n }\n .force-graph-dev-controls h3 {\n margin: 0 0 12px 0;\n font-size: 14px;\n color: #60a5fa;\n }\n .force-graph-dev-controls .control-group {\n margin-bottom: 12px;\n }\n .force-graph-dev-controls label {\n display: block;\n margin-bottom: 4px;\n color: rgba(255, 255, 255, 0.7);\n }\n .force-graph-dev-controls input[type=\"range\"] {\n width: 100%;\n margin-top: 4px;\n }\n .force-graph-dev-controls .value {\n color: #60a5fa;\n font-weight: 600;\n }\n .force-graph-dev-controls .stats {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n }\n </style>\n <h3>⚙️ Dev Controls</h3>\n <div class=\"control-group\">\n <label>Repulsion: <span class=\"value\" id=\"dev-repulsion-val\">${this.options.repulsionStrength}</span></label>\n <input type=\"range\" id=\"dev-repulsion\" min=\"10\" max=\"500\" value=\"${this.options.repulsionStrength}\">\n </div>\n <div class=\"control-group\">\n <label>Attraction: <span class=\"value\" id=\"dev-attraction-val\">${(this.options.attractionStrength ?? 0.01).toFixed(3)}</span></label>\n <input type=\"range\" id=\"dev-attraction\" min=\"1\" max=\"100\" value=\"${(this.options.attractionStrength ?? 0.01) * 1000}\">\n </div>\n <div class=\"control-group\">\n <label>Damping: <span class=\"value\" id=\"dev-damping-val\">${this.options.damping}</span></label>\n <input type=\"range\" id=\"dev-damping\" min=\"50\" max=\"99\" value=\"${(this.options.damping ?? 0.9) * 100}\">\n </div>\n <div class=\"stats\">\n <div>Nodes: <span class=\"value\" id=\"dev-node-count\">0</span></div>\n <div>Edges: <span class=\"value\" id=\"dev-edge-count\">0</span></div>\n <div>FPS: <span class=\"value\" id=\"dev-fps\">60</span></div>\n </div>\n `;\n\n this.container.appendChild(this.devControls);\n\n // Setup event listeners\n const repulsionSlider = this.devControls.querySelector('#dev-repulsion') as HTMLInputElement;\n const attractionSlider = this.devControls.querySelector('#dev-attraction') as HTMLInputElement;\n const dampingSlider = this.devControls.querySelector('#dev-damping') as HTMLInputElement;\n\n repulsionSlider?.addEventListener('input', () => {\n const value = parseFloat(repulsionSlider.value);\n this.setPhysicsParams({ repulsionStrength: value });\n (this.devControls!.querySelector('#dev-repulsion-val') as HTMLElement).textContent = value.toString();\n });\n\n attractionSlider?.addEventListener('input', () => {\n const value = parseFloat(attractionSlider.value) / 1000;\n this.setPhysicsParams({ attractionStrength: value });\n (this.devControls!.querySelector('#dev-attraction-val') as HTMLElement).textContent = value.toFixed(3);\n });\n\n dampingSlider?.addEventListener('input', () => {\n const value = parseFloat(dampingSlider.value) / 100;\n this.setPhysicsParams({ damping: value });\n (this.devControls!.querySelector('#dev-damping-val') as HTMLElement).textContent = value.toFixed(2);\n });\n\n // Update stats periodically\n setInterval(() => {\n const nodeCount = this.devControls!.querySelector('#dev-node-count');\n const edgeCount = this.devControls!.querySelector('#dev-edge-count');\n const fps = this.devControls!.querySelector('#dev-fps');\n\n if (nodeCount) nodeCount.textContent = this.getNodeCount().toString();\n if (edgeCount) edgeCount.textContent = this.getEdgeCount().toString();\n if (fps) fps.textContent = this.rendererManager.getFPS().toString();\n }, 500);\n }\n\n /**\n * Destroys the graph and releases all resources\n */\n destroy(): void {\n // Stop animation\n this.rendererManager.dispose();\n\n // Dispose interaction\n this.panelManager.dispose();\n this.raycasterManager.dispose();\n this.edgeTooltipManager.dispose();\n if (this.searchManager) {\n this.searchManager.dispose();\n }\n if (this.viewToggleManager) {\n this.viewToggleManager.dispose();\n }\n\n // Dispose 2D renderer\n if (this.forceGraph2D) {\n this.forceGraph2D.dispose();\n }\n\n // Dispose managers\n this.edgeManager.dispose();\n this.nodeManager.dispose();\n\n // Dispose factories\n this.nodeFactory.dispose();\n this.materialFactory.dispose();\n\n // Dispose scene\n this.sceneManager.dispose();\n\n // Remove dev controls\n if (this.devControls && this.devControls.parentNode) {\n this.devControls.parentNode.removeChild(this.devControls);\n }\n\n // Clear event callbacks\n this.eventCallbacks.clear();\n\n this.initialized = false;\n }\n}\n","import type { GraphData, NodeData, Edge } from '../utils/types';\n\n/**\n * Sample Data Generator\n * Generates sample graph data for testing and demos\n */\n\nconst NODE_LABELS = [\n 'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon',\n 'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa',\n 'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron',\n 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon',\n 'Phi', 'Chi', 'Psi', 'Omega', 'Core',\n 'Hub', 'Node', 'Link', 'Point', 'Vertex',\n];\n\nconst RELATIONSHIPS = [\n 'connects to',\n 'links with',\n 'relates to',\n 'depends on',\n 'references',\n 'extends',\n 'includes',\n 'partners with',\n 'collaborates with',\n 'supports',\n];\n\n// White and tangerine color palette\nconst NODE_COLORS = [\n 0xffffff, // White\n 0xff9966, // Tangerine\n 0xffcc99, // Light peach\n 0xffeedd, // Cream\n 0xff8844, // Darker tangerine\n];\n\n/**\n * Generates sample graph data with the specified number of nodes\n */\nexport function generateSampleData(nodeCount: number = 30): GraphData {\n const nodes: NodeData[] = [];\n const edges: Edge[] = [];\n\n // Create nodes with white/tangerine colors\n for (let i = 0; i < nodeCount; i++) {\n const label = i < NODE_LABELS.length\n ? NODE_LABELS[i]\n : `Node ${i + 1}`;\n\n nodes.push({\n id: `node-${i}`,\n label: label,\n color: NODE_COLORS[i % NODE_COLORS.length],\n position: {\n x: (Math.random() - 0.5) * 60,\n y: (Math.random() - 0.5) * 60,\n z: (Math.random() - 0.5) * 60,\n },\n });\n }\n\n // Create a connected graph\n // First, create a spanning tree to ensure connectivity\n for (let i = 1; i < nodeCount; i++) {\n const targetIndex = Math.floor(Math.random() * i);\n edges.push({\n source: `node-${i}`,\n target: `node-${targetIndex}`,\n relationship: RELATIONSHIPS[Math.floor(Math.random() * RELATIONSHIPS.length)],\n });\n }\n\n // Add some extra edges for more connectivity\n const extraEdges = Math.floor(nodeCount * 0.5);\n for (let i = 0; i < extraEdges; i++) {\n const sourceIndex = Math.floor(Math.random() * nodeCount);\n let targetIndex = Math.floor(Math.random() * nodeCount);\n\n // Avoid self-loops and ensure different nodes\n if (sourceIndex === targetIndex) {\n targetIndex = (targetIndex + 1) % nodeCount;\n }\n\n const source = `node-${sourceIndex}`;\n const target = `node-${targetIndex}`;\n\n // Check if edge already exists (will be handled by EdgeManager anyway)\n const edgeExists = edges.some(e =>\n (e.source === source && e.target === target) ||\n (e.source === target && e.target === source)\n );\n\n if (!edgeExists) {\n edges.push({\n source,\n target,\n relationship: RELATIONSHIPS[Math.floor(Math.random() * RELATIONSHIPS.length)],\n });\n }\n }\n\n return { nodes, edges };\n}\n\n/**\n * Generates a large sample dataset for performance testing\n */\nexport function generateLargeSampleData(nodeCount: number = 1000): GraphData {\n const nodes: NodeData[] = [];\n const edges: Edge[] = [];\n\n // Create nodes in clusters\n const clusterCount = Math.ceil(nodeCount / 50);\n const clusterCenters: Array<{ x: number; y: number; z: number }> = [];\n\n // Generate cluster centers\n for (let c = 0; c < clusterCount; c++) {\n clusterCenters.push({\n x: (Math.random() - 0.5) * 200,\n y: (Math.random() - 0.5) * 200,\n z: (Math.random() - 0.5) * 200,\n });\n }\n\n // Create nodes (no colors - clear glass)\n for (let i = 0; i < nodeCount; i++) {\n const cluster = clusterCenters[i % clusterCount];\n\n nodes.push({\n id: `node-${i}`,\n label: `N${i}`,\n position: {\n x: cluster.x + (Math.random() - 0.5) * 40,\n y: cluster.y + (Math.random() - 0.5) * 40,\n z: cluster.z + (Math.random() - 0.5) * 40,\n },\n });\n }\n\n // Create spanning tree for connectivity\n for (let i = 1; i < nodeCount; i++) {\n // Connect to a node in the same cluster or previous\n const clusterStart = Math.floor(i / 50) * 50;\n const targetIndex = clusterStart === 0\n ? Math.floor(Math.random() * i)\n : clusterStart + Math.floor(Math.random() * Math.min(i - clusterStart, 50));\n\n edges.push({\n source: `node-${i}`,\n target: `node-${Math.min(targetIndex, i - 1)}`,\n relationship: 'links to',\n });\n }\n\n // Connect clusters\n for (let c = 1; c < clusterCount; c++) {\n const sourceNode = c * 50;\n const targetNode = (c - 1) * 50 + Math.floor(Math.random() * 50);\n edges.push({\n source: `node-${sourceNode}`,\n target: `node-${targetNode}`,\n relationship: 'bridges to',\n });\n }\n\n return { nodes, edges };\n}\n"],"names":["DEFAULT_OPTIONS","LODLevel","createContainer","container","validateContainer","getContainerDimensions","rect","validateNodeData","node","n","isValidPosition","validateEdgeData","edge","validateNodeId","id","pos","p","createEdgeKey","source","target","_changeEvent","_startEvent","_endEvent","_ray","Ray","_plane","Plane","TILT_LIMIT","MathUtils","OrbitControls","EventDispatcher","object","domElement","Vector3","MOUSE","TOUCH","spherical","onKeyDown","scope","state","STATE","offset","quat","Quaternion","quatInverse","lastPosition","lastQuaternion","lastTargetPosition","twoPI","deltaTime","position","rotateLeft","getAutoRotationAngle","sphericalDelta","min","max","panOffset","performCursorZoom","clampDistance","scale","zoomChanged","newRadius","prevRadius","radiusDelta","dollyDirection","mouseBefore","mouse","mouseAfter","EPS","onContextMenu","onPointerDown","onPointerUp","onMouseWheel","onPointerMove","Spherical","rotateStart","Vector2","rotateEnd","rotateDelta","panStart","panEnd","panDelta","dollyStart","dollyEnd","dollyDelta","pointers","pointerPositions","controlActive","getZoomScale","delta","normalizedDelta","angle","rotateUp","panLeft","v","distance","objectMatrix","panUp","pan","deltaX","deltaY","element","targetDistance","dollyOut","dollyScale","dollyIn","updateZoomParameters","x","y","dx","dy","w","h","dist","handleMouseDownRotate","event","handleMouseDownDolly","handleMouseDownPan","handleMouseMoveRotate","handleMouseMoveDolly","handleMouseMovePan","handleMouseWheel","handleKeyDown","needsUpdate","handleTouchStartRotate","getSecondPointerPosition","handleTouchStartPan","handleTouchStartDolly","handleTouchStartDollyPan","handleTouchStartDollyRotate","handleTouchMoveRotate","handleTouchMovePan","handleTouchMoveDolly","centerX","centerY","handleTouchMoveDollyPan","handleTouchMoveDollyRotate","addPointer","onTouchStart","onMouseDown","onTouchMove","onMouseMove","removePointer","mouseAction","customWheelEvent","mode","newEvent","interceptControlDown","interceptControlUp","trackPointer","i","pointerId","SceneManager","options","__publicField","THREE","width","height","fov","camPos","ambientLight","keyLight","fillLight","rimLight","accentLight1","accentLight2","accentLight3","direction","child","NodeManager","sceneManager","nodeFactory","nodeId","nodeData","lodLevel","internalNode","nodeObject","updates","key","objects","spheres","_","EdgeManager","nodeManager","edgeFactory","edgeData","edgeKey","sourceNode","targetNode","edgeObject","index","e","edgesToRemove","neighbors","eo","GraphEngine","nodes","edges","nodeCount","nodesArray","nodeA","j","nodeB","dz","distSq","force","fx","fy","fz","octree","Octree","octreeNode","params","bounds","padding","depth","size","totalMass","com","midX","midY","midZ","octants","idx","childBounds","children","RendererManager","onSimulate","onRender","targetFPS","currentTime","elapsed","fpsElapsed","fps","MaterialFactory","faces","faceConfigs","config","faceCanvas","faceCtx","gradient","imageData","noise","c","img","_color","cacheKey","threeColor","material","color","opacity","text","fontSize","canvas","ctx","textWidth","texture","NodeFactory","materialFactory","nodeRadius","lodSegments","defaultNodeColor","segments","group","geometry","sphere","labelMaterial","label","newLodLevel","newGeometry","EdgeFactory","edgeColor","edgeOpacity","sourcePos","targetPos","positions","line","posArray","LODManager","camera","lodDistances","enabled","LODLevelEnum","maxDistance","distances","FrustumCuller","point","radius","start","end","startPoint","endPoint","center","RaycasterManager","callback","edgeInfo","newHoveredNodeId","newHoveredEdgeKey","intersects","obj","_a","userData","screenX","screenY","PanelManager","value","template","styles","content","expandBtn","depthSelect","closeBtn","colorHex","div","EdgePanelManager","sourceBtn","targetBtn","sourceColorHex","targetColorHex","relationship","EdgeTooltipManager","mouseX","mouseY","tooltipRect","viewportWidth","viewportHeight","left","top","SearchManager","wrapper","style","query","nodeResults","edgeResults","html","typeLabel","item","ViewToggleManager","btn2D","btn3D","btn","DEFAULT_2D_OPTIONS","ForceGraph2D","dpr","zoomFactor","newScale","scaleChange","worldPos","wasClick","lengthSq","t","projX","projY","distX","distY","animate","minDistance","maxVelocity","totalEnergy","targetDist","speed","gridSize","dotRadius","offsetX","offsetY","isHovered","isSelected","isConnectedToHoveredEdge","glowGradient","alpha","nodeGradient","r","g","b","maxWidth","data","targetX","targetY","startX","startY","duration","startTime","progress","eased","nodesMap","node3d","node2d","ForceGraph3D","info","success","fetchFn","expandCallback","newData","error","controls","newCameraPos","startCameraPos","startTarget","sourceId","targetId","midpoint","nodeDistance","cameraDistance","lowerQuery","results","labelMatch","idMatch","_b","typeMatch","_c","allEdges","args","callbacks","cb","repulsionSlider","attractionSlider","dampingSlider","edgeCount","NODE_LABELS","RELATIONSHIPS","NODE_COLORS","generateSampleData","targetIndex","extraEdges","sourceIndex","generateLargeSampleData","clusterCount","clusterCenters","cluster","clusterStart"],"mappings":"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","x_google_ignoreList":[3]}
|
|
1
|
+
{"version":3,"file":"force-3d-graph.js","sources":["../src/utils/types.ts","../src/utils/ContainerManager.ts","../src/utils/validation.ts","../node_modules/three/examples/jsm/controls/OrbitControls.js","../src/core/SceneManager.ts","../src/core/NodeManager.ts","../src/core/EdgeManager.ts","../src/core/GraphEngine.ts","../src/core/RendererManager.ts","../src/factory/MaterialFactory.ts","../src/factory/NodeFactory.ts","../src/factory/EdgeFactory.ts","../src/performance/LODManager.ts","../src/performance/FrustumCuller.ts","../src/interaction/RaycasterManager.ts","../src/interaction/PanelManager.ts","../src/interaction/EdgePanelManager.ts","../src/interaction/EdgeTooltipManager.ts","../src/interaction/SearchManager.ts","../src/interaction/ViewToggleManager.ts","../src/core/ForceGraph2D.ts","../src/ForceGraph3D.ts","../src/test/sampleData.ts"],"sourcesContent":["// Global type declaration for __DEV__ flag\ndeclare const __DEV__: boolean;\n\n// ============================================================================\n// Data Interfaces (User-facing)\n// ============================================================================\n\n/**\n * Node data provided by the user\n */\nexport interface NodeData {\n /** Unique identifier for the node */\n id: string;\n /** Display label for the node */\n label: string;\n /** Optional hex color (default: 0x4A90E2) */\n color?: number;\n /** Optional initial position (random if not provided) */\n position?: Vector3Data;\n /** Additional custom data */\n [key: string]: unknown;\n}\n\n/**\n * Edge data provided by the user\n */\nexport interface Edge {\n /** Source node ID */\n source: string;\n /** Target node ID */\n target: string;\n /** Optional relationship label */\n relationship?: string;\n /** Optional label (alias for relationship) */\n label?: string;\n /** Additional custom data */\n [key: string]: unknown;\n}\n\n/**\n * Graph data structure\n */\nexport interface GraphData {\n nodes: NodeData[];\n /** Edges array (also accepts 'links' as alias) */\n edges?: Edge[];\n /** Links array (alias for edges, used by some APIs) */\n links?: Edge[];\n}\n\n/**\n * Simple 3D vector\n */\nexport interface Vector3Data {\n x: number;\n y: number;\n z: number;\n}\n\n// ============================================================================\n// Internal Interfaces\n// ============================================================================\n\n/**\n * Internal node representation with physics state\n */\nexport interface InternalNode extends NodeData {\n position: Vector3Data;\n velocity: Vector3Data;\n mass: number;\n}\n\n/**\n * Internal edge representation\n */\nexport interface InternalEdge extends Edge {\n sourceNode: InternalNode;\n targetNode: InternalNode;\n}\n\n// ============================================================================\n// Configuration Interfaces\n// ============================================================================\n\n/**\n * Constructor options for ForceGraph3D\n */\nexport interface ForceGraph3DOptions {\n // Container element (optional - will create if not provided)\n container?: HTMLElement | null;\n\n // Scene configuration\n backgroundColor?: number | string;\n cameraPosition?: Vector3Data;\n cameraFov?: number;\n\n // Physics parameters\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n useBarnesHut?: boolean;\n barnesHutTheta?: number;\n\n // Node appearance\n defaultNodeColor?: number;\n nodeRadius?: number;\n nodeSegments?: number;\n\n // LOD configuration\n enableLOD?: boolean;\n lodDistances?: number[];\n lodSegments?: number[];\n\n // Edge appearance\n edgeColor?: number;\n edgeOpacity?: number;\n enableEdgeCulling?: boolean;\n\n // Panel configuration\n showPanel?: boolean;\n panelTemplate?: (nodeData: NodeData, neighbors: NodeData[]) => string;\n panelStyles?: Record<string, string>;\n\n // Search configuration\n showSearch?: boolean;\n searchPlaceholder?: string;\n\n // View mode configuration\n initialViewMode?: '2d' | '3d';\n showViewToggle?: boolean;\n\n // Performance\n targetFPS?: number;\n maxVisibleNodes?: number;\n\n // Event callbacks\n onNodeClick?: (nodeData: NodeData) => void;\n onNodeHover?: (nodeData: NodeData | null) => void;\n onEdgeHover?: (edge: Edge | null, sourceNode: NodeData | null, targetNode: NodeData | null) => void;\n onNodeAdd?: (nodeData: NodeData) => void;\n onNodeRemove?: (nodeId: string) => void;\n onEdgeAdd?: (edge: Edge) => void;\n onEdgeRemove?: (edge: Edge) => void;\n onExpand?: (nodeId: string, depth?: number) => Promise<GraphData>;\n}\n\n/**\n * Default options\n */\nexport const DEFAULT_OPTIONS: Required<Omit<ForceGraph3DOptions, 'container' | 'onNodeClick' | 'onNodeHover' | 'onEdgeHover' | 'onNodeAdd' | 'onNodeRemove' | 'onEdgeAdd' | 'onEdgeRemove' | 'onExpand' | 'panelTemplate' | 'panelStyles'>> = {\n backgroundColor: 0x0a0a0a,\n cameraPosition: { x: 0, y: 0, z: 80 },\n cameraFov: 75,\n\n repulsionStrength: 200,\n attractionStrength: 0.008,\n damping: 0.95,\n useBarnesHut: true, // Enabled by default for better performance\n barnesHutTheta: 0.5,\n\n defaultNodeColor: 0xff9966, // Tangerine to match the premium glass material\n nodeRadius: 2,\n nodeSegments: 32,\n\n enableLOD: true,\n lodDistances: [50, 100, 200],\n lodSegments: [32, 16, 8],\n\n edgeColor: 0x888888,\n edgeOpacity: 0.4,\n enableEdgeCulling: true,\n\n showPanel: true,\n showSearch: true,\n searchPlaceholder: 'Search nodes or relationships...',\n\n initialViewMode: '3d',\n showViewToggle: true,\n\n targetFPS: 60,\n maxVisibleNodes: 10000,\n};\n\n// ============================================================================\n// Event Types\n// ============================================================================\n\nexport type EventType =\n | 'nodeClick'\n | 'nodeHover'\n | 'edgeHover'\n | 'edgeClick'\n | 'nodeAdd'\n | 'nodeRemove'\n | 'edgeAdd'\n | 'edgeRemove'\n | 'expand'\n | 'viewChange'\n | 'ready';\n\nexport type EventCallback = (...args: unknown[]) => void;\n\n// ============================================================================\n// LOD Types\n// ============================================================================\n\nexport enum LODLevel {\n HIGH = 0,\n MEDIUM = 1,\n LOW = 2,\n}\n\n// ============================================================================\n// Three.js Object References\n// ============================================================================\n\nexport interface NodeObject {\n group: THREE.Group;\n sphere: THREE.Mesh;\n label: THREE.Sprite;\n lodLevel: LODLevel;\n}\n\nexport interface EdgeObject {\n line: THREE.Line;\n source: string;\n target: string;\n}\n\n// Import Three.js types for reference\nimport type * as THREE from 'three';\n","/**\n * Container management utility\n * Auto-creates a container div if none is provided\n */\n\nexport function createContainer(): HTMLElement {\n const container = document.createElement('div');\n container.id = 'force-graph-3d-container';\n container.style.cssText = `\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n overflow: hidden;\n `;\n document.body.appendChild(container);\n return container;\n}\n\nexport function validateContainer(container: HTMLElement | null | undefined): HTMLElement {\n if (container && container instanceof HTMLElement) {\n return container;\n }\n console.warn('[ForceGraph3D] No container provided, creating one automatically');\n return createContainer();\n}\n\nexport function getContainerDimensions(container: HTMLElement): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: rect.width || window.innerWidth,\n height: rect.height || window.innerHeight,\n };\n}\n","import type { NodeData, Edge } from './types';\n\n/**\n * Validates node data\n * @returns true if valid, false otherwise (logs warning)\n */\nexport function validateNodeData(node: unknown): node is NodeData {\n if (!node || typeof node !== 'object') {\n console.warn('[ForceGraph3D] Invalid node: must be an object');\n return false;\n }\n\n const n = node as Record<string, unknown>;\n\n if (typeof n.id !== 'string' || n.id.trim() === '') {\n console.warn('[ForceGraph3D] Invalid node: id must be a non-empty string');\n return false;\n }\n\n if (typeof n.label !== 'string') {\n console.warn('[ForceGraph3D] Invalid node: label must be a string');\n return false;\n }\n\n if (n.color !== undefined && typeof n.color !== 'number') {\n console.warn('[ForceGraph3D] Invalid node: color must be a number (hex)');\n return false;\n }\n\n if (n.position !== undefined) {\n if (!isValidPosition(n.position)) {\n console.warn('[ForceGraph3D] Invalid node: position must have x, y, z numbers');\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Validates edge data\n * @returns true if valid, false otherwise (logs warning)\n */\nexport function validateEdgeData(edge: unknown): edge is Edge {\n if (!edge || typeof edge !== 'object') {\n console.warn('[ForceGraph3D] Invalid edge: must be an object');\n return false;\n }\n\n const e = edge as Record<string, unknown>;\n\n if (typeof e.source !== 'string' || e.source.trim() === '') {\n console.warn('[ForceGraph3D] Invalid edge: source must be a non-empty string');\n return false;\n }\n\n if (typeof e.target !== 'string' || e.target.trim() === '') {\n console.warn('[ForceGraph3D] Invalid edge: target must be a non-empty string');\n return false;\n }\n\n return true;\n}\n\n/**\n * Validates a node ID\n */\nexport function validateNodeId(id: unknown): id is string {\n if (typeof id !== 'string' || id.trim() === '') {\n console.warn('[ForceGraph3D] Invalid node ID: must be a non-empty string');\n return false;\n }\n return true;\n}\n\n/**\n * Validates a position object\n */\nfunction isValidPosition(pos: unknown): pos is { x: number; y: number; z: number } {\n if (!pos || typeof pos !== 'object') return false;\n const p = pos as Record<string, unknown>;\n return (\n typeof p.x === 'number' &&\n typeof p.y === 'number' &&\n typeof p.z === 'number'\n );\n}\n\n/**\n * Creates a normalized edge key for duplicate detection\n * Always puts the smaller ID first to handle bidirectional edges\n */\nexport function createEdgeKey(source: string, target: string): string {\n // For self-loops, just use the single ID\n if (source === target) {\n return `${source}-${target}`;\n }\n // Normalize direction for duplicate detection\n return source < target ? `${source}-${target}` : `${target}-${source}`;\n}\n","import {\n\tEventDispatcher,\n\tMOUSE,\n\tQuaternion,\n\tSpherical,\n\tTOUCH,\n\tVector2,\n\tVector3,\n\tPlane,\n\tRay,\n\tMathUtils\n} from 'three';\n\n// OrbitControls performs orbiting, dollying (zooming), and panning.\n// Unlike TrackballControls, it maintains the \"up\" direction object.up (+Y by default).\n//\n// Orbit - left mouse / touch: one-finger move\n// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish\n// Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move\n\nconst _changeEvent = { type: 'change' };\nconst _startEvent = { type: 'start' };\nconst _endEvent = { type: 'end' };\nconst _ray = new Ray();\nconst _plane = new Plane();\nconst TILT_LIMIT = Math.cos( 70 * MathUtils.DEG2RAD );\n\nclass OrbitControls extends EventDispatcher {\n\n\tconstructor( object, domElement ) {\n\n\t\tsuper();\n\n\t\tthis.object = object;\n\t\tthis.domElement = domElement;\n\t\tthis.domElement.style.touchAction = 'none'; // disable touch scroll\n\n\t\t// Set to false to disable this control\n\t\tthis.enabled = true;\n\n\t\t// \"target\" sets the location of focus, where the object orbits around\n\t\tthis.target = new Vector3();\n\n\t\t// Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect\n\t\tthis.cursor = new Vector3();\n\n\t\t// How far you can dolly in and out ( PerspectiveCamera only )\n\t\tthis.minDistance = 0;\n\t\tthis.maxDistance = Infinity;\n\n\t\t// How far you can zoom in and out ( OrthographicCamera only )\n\t\tthis.minZoom = 0;\n\t\tthis.maxZoom = Infinity;\n\n\t\t// Limit camera target within a spherical area around the cursor\n\t\tthis.minTargetRadius = 0;\n\t\tthis.maxTargetRadius = Infinity;\n\n\t\t// How far you can orbit vertically, upper and lower limits.\n\t\t// Range is 0 to Math.PI radians.\n\t\tthis.minPolarAngle = 0; // radians\n\t\tthis.maxPolarAngle = Math.PI; // radians\n\n\t\t// How far you can orbit horizontally, upper and lower limits.\n\t\t// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )\n\t\tthis.minAzimuthAngle = - Infinity; // radians\n\t\tthis.maxAzimuthAngle = Infinity; // radians\n\n\t\t// Set to true to enable damping (inertia)\n\t\t// If damping is enabled, you must call controls.update() in your animation loop\n\t\tthis.enableDamping = false;\n\t\tthis.dampingFactor = 0.05;\n\n\t\t// This option actually enables dollying in and out; left as \"zoom\" for backwards compatibility.\n\t\t// Set to false to disable zooming\n\t\tthis.enableZoom = true;\n\t\tthis.zoomSpeed = 1.0;\n\n\t\t// Set to false to disable rotating\n\t\tthis.enableRotate = true;\n\t\tthis.rotateSpeed = 1.0;\n\n\t\t// Set to false to disable panning\n\t\tthis.enablePan = true;\n\t\tthis.panSpeed = 1.0;\n\t\tthis.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up\n\t\tthis.keyPanSpeed = 7.0;\t// pixels moved per arrow key push\n\t\tthis.zoomToCursor = false;\n\n\t\t// Set to true to automatically rotate around the target\n\t\t// If auto-rotate is enabled, you must call controls.update() in your animation loop\n\t\tthis.autoRotate = false;\n\t\tthis.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60\n\n\t\t// The four arrow keys\n\t\tthis.keys = { LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' };\n\n\t\t// Mouse buttons\n\t\tthis.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };\n\n\t\t// Touch fingers\n\t\tthis.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };\n\n\t\t// for reset\n\t\tthis.target0 = this.target.clone();\n\t\tthis.position0 = this.object.position.clone();\n\t\tthis.zoom0 = this.object.zoom;\n\n\t\t// the target DOM element for key events\n\t\tthis._domElementKeyEvents = null;\n\n\t\t//\n\t\t// public methods\n\t\t//\n\n\t\tthis.getPolarAngle = function () {\n\n\t\t\treturn spherical.phi;\n\n\t\t};\n\n\t\tthis.getAzimuthalAngle = function () {\n\n\t\t\treturn spherical.theta;\n\n\t\t};\n\n\t\tthis.getDistance = function () {\n\n\t\t\treturn this.object.position.distanceTo( this.target );\n\n\t\t};\n\n\t\tthis.listenToKeyEvents = function ( domElement ) {\n\n\t\t\tdomElement.addEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = domElement;\n\n\t\t};\n\n\t\tthis.stopListenToKeyEvents = function () {\n\n\t\t\tthis._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = null;\n\n\t\t};\n\n\t\tthis.saveState = function () {\n\n\t\t\tscope.target0.copy( scope.target );\n\t\t\tscope.position0.copy( scope.object.position );\n\t\t\tscope.zoom0 = scope.object.zoom;\n\n\t\t};\n\n\t\tthis.reset = function () {\n\n\t\t\tscope.target.copy( scope.target0 );\n\t\t\tscope.object.position.copy( scope.position0 );\n\t\t\tscope.object.zoom = scope.zoom0;\n\n\t\t\tscope.object.updateProjectionMatrix();\n\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\tscope.update();\n\n\t\t\tstate = STATE.NONE;\n\n\t\t};\n\n\t\t// this method is exposed, but perhaps it would be better if we can make it private...\n\t\tthis.update = function () {\n\n\t\t\tconst offset = new Vector3();\n\n\t\t\t// so camera.up is the orbit axis\n\t\t\tconst quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) );\n\t\t\tconst quatInverse = quat.clone().invert();\n\n\t\t\tconst lastPosition = new Vector3();\n\t\t\tconst lastQuaternion = new Quaternion();\n\t\t\tconst lastTargetPosition = new Vector3();\n\n\t\t\tconst twoPI = 2 * Math.PI;\n\n\t\t\treturn function update( deltaTime = null ) {\n\n\t\t\t\tconst position = scope.object.position;\n\n\t\t\t\toffset.copy( position ).sub( scope.target );\n\n\t\t\t\t// rotate offset to \"y-axis-is-up\" space\n\t\t\t\toffset.applyQuaternion( quat );\n\n\t\t\t\t// angle from z-axis around y-axis\n\t\t\t\tspherical.setFromVector3( offset );\n\n\t\t\t\tif ( scope.autoRotate && state === STATE.NONE ) {\n\n\t\t\t\t\trotateLeft( getAutoRotationAngle( deltaTime ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( scope.enableDamping ) {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta * scope.dampingFactor;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi * scope.dampingFactor;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi;\n\n\t\t\t\t}\n\n\t\t\t\t// restrict theta to be between desired limits\n\n\t\t\t\tlet min = scope.minAzimuthAngle;\n\t\t\t\tlet max = scope.maxAzimuthAngle;\n\n\t\t\t\tif ( isFinite( min ) && isFinite( max ) ) {\n\n\t\t\t\t\tif ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI;\n\n\t\t\t\t\tif ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI;\n\n\t\t\t\t\tif ( min <= max ) {\n\n\t\t\t\t\t\tspherical.theta = Math.max( min, Math.min( max, spherical.theta ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tspherical.theta = ( spherical.theta > ( min + max ) / 2 ) ?\n\t\t\t\t\t\t\tMath.max( min, spherical.theta ) :\n\t\t\t\t\t\t\tMath.min( max, spherical.theta );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// restrict phi to be between desired limits\n\t\t\t\tspherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );\n\n\t\t\t\tspherical.makeSafe();\n\n\n\t\t\t\t// move target to panned location\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tscope.target.addScaledVector( panOffset, scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tscope.target.add( panOffset );\n\n\t\t\t\t}\n\n\t\t\t\t// Limit the target distance from the cursor to create a sphere around the center of interest\n\t\t\t\tscope.target.sub( scope.cursor );\n\t\t\t\tscope.target.clampLength( scope.minTargetRadius, scope.maxTargetRadius );\n\t\t\t\tscope.target.add( scope.cursor );\n\n\t\t\t\t// adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera\n\t\t\t\t// we adjust zoom later in these cases\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius * scale );\n\n\t\t\t\t}\n\n\t\t\t\toffset.setFromSpherical( spherical );\n\n\t\t\t\t// rotate offset back to \"camera-up-vector-is-up\" space\n\t\t\t\toffset.applyQuaternion( quatInverse );\n\n\t\t\t\tposition.copy( scope.target ).add( offset );\n\n\t\t\t\tscope.object.lookAt( scope.target );\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tsphericalDelta.theta *= ( 1 - scope.dampingFactor );\n\t\t\t\t\tsphericalDelta.phi *= ( 1 - scope.dampingFactor );\n\n\t\t\t\t\tpanOffset.multiplyScalar( 1 - scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsphericalDelta.set( 0, 0, 0 );\n\n\t\t\t\t\tpanOffset.set( 0, 0, 0 );\n\n\t\t\t\t}\n\n\t\t\t\t// adjust camera position\n\t\t\t\tlet zoomChanged = false;\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom ) {\n\n\t\t\t\t\tlet newRadius = null;\n\t\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t\t// move the camera down the pointer ray\n\t\t\t\t\t\t// this method avoids floating point error\n\t\t\t\t\t\tconst prevRadius = offset.length();\n\t\t\t\t\t\tnewRadius = clampDistance( prevRadius * scale );\n\n\t\t\t\t\t\tconst radiusDelta = prevRadius - newRadius;\n\t\t\t\t\t\tscope.object.position.addScaledVector( dollyDirection, radiusDelta );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t\t// adjust the ortho camera position based on zoom changes\n\t\t\t\t\t\tconst mouseBefore = new Vector3( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseBefore.unproject( scope.object );\n\n\t\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\t\t\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\t\t\tzoomChanged = true;\n\n\t\t\t\t\t\tconst mouseAfter = new Vector3( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseAfter.unproject( scope.object );\n\n\t\t\t\t\t\tscope.object.position.sub( mouseAfter ).add( mouseBefore );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t\tnewRadius = offset.length();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.' );\n\t\t\t\t\t\tscope.zoomToCursor = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// handle the placement of the target\n\t\t\t\t\tif ( newRadius !== null ) {\n\n\t\t\t\t\t\tif ( this.screenSpacePanning ) {\n\n\t\t\t\t\t\t\t// position the orbit target in front of the new camera position\n\t\t\t\t\t\t\tscope.target.set( 0, 0, - 1 )\n\t\t\t\t\t\t\t\t.transformDirection( scope.object.matrix )\n\t\t\t\t\t\t\t\t.multiplyScalar( newRadius )\n\t\t\t\t\t\t\t\t.add( scope.object.position );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// get the ray and translation plane to compute target\n\t\t\t\t\t\t\t_ray.origin.copy( scope.object.position );\n\t\t\t\t\t\t\t_ray.direction.set( 0, 0, - 1 ).transformDirection( scope.object.matrix );\n\n\t\t\t\t\t\t\t// if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid\n\t\t\t\t\t\t\t// extremely large values\n\t\t\t\t\t\t\tif ( Math.abs( scope.object.up.dot( _ray.direction ) ) < TILT_LIMIT ) {\n\n\t\t\t\t\t\t\t\tobject.lookAt( scope.target );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t_plane.setFromNormalAndCoplanarPoint( scope.object.up, scope.target );\n\t\t\t\t\t\t\t\t_ray.intersectPlane( _plane, scope.target );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\t\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\t\tzoomChanged = true;\n\n\t\t\t\t}\n\n\t\t\t\tscale = 1;\n\t\t\t\tperformCursorZoom = false;\n\n\t\t\t\t// update condition is:\n\t\t\t\t// min(camera displacement, camera rotation in radians)^2 > EPS\n\t\t\t\t// using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n\t\t\t\tif ( zoomChanged ||\n\t\t\t\t\tlastPosition.distanceToSquared( scope.object.position ) > EPS ||\n\t\t\t\t\t8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ||\n\t\t\t\t\tlastTargetPosition.distanceToSquared( scope.target ) > 0 ) {\n\n\t\t\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\t\t\tlastPosition.copy( scope.object.position );\n\t\t\t\t\tlastQuaternion.copy( scope.object.quaternion );\n\t\t\t\t\tlastTargetPosition.copy( scope.target );\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t};\n\n\t\t}();\n\n\t\tthis.dispose = function () {\n\n\t\t\tscope.domElement.removeEventListener( 'contextmenu', onContextMenu );\n\n\t\t\tscope.domElement.removeEventListener( 'pointerdown', onPointerDown );\n\t\t\tscope.domElement.removeEventListener( 'pointercancel', onPointerUp );\n\t\t\tscope.domElement.removeEventListener( 'wheel', onMouseWheel );\n\n\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\n\t\t\tif ( scope._domElementKeyEvents !== null ) {\n\n\t\t\t\tscope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\t\tscope._domElementKeyEvents = null;\n\n\t\t\t}\n\n\t\t\t//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?\n\n\t\t};\n\n\t\t//\n\t\t// internals\n\t\t//\n\n\t\tconst scope = this;\n\n\t\tconst STATE = {\n\t\t\tNONE: - 1,\n\t\t\tROTATE: 0,\n\t\t\tDOLLY: 1,\n\t\t\tPAN: 2,\n\t\t\tTOUCH_ROTATE: 3,\n\t\t\tTOUCH_PAN: 4,\n\t\t\tTOUCH_DOLLY_PAN: 5,\n\t\t\tTOUCH_DOLLY_ROTATE: 6\n\t\t};\n\n\t\tlet state = STATE.NONE;\n\n\t\tconst EPS = 0.000001;\n\n\t\t// current position in spherical coordinates\n\t\tconst spherical = new Spherical();\n\t\tconst sphericalDelta = new Spherical();\n\n\t\tlet scale = 1;\n\t\tconst panOffset = new Vector3();\n\n\t\tconst rotateStart = new Vector2();\n\t\tconst rotateEnd = new Vector2();\n\t\tconst rotateDelta = new Vector2();\n\n\t\tconst panStart = new Vector2();\n\t\tconst panEnd = new Vector2();\n\t\tconst panDelta = new Vector2();\n\n\t\tconst dollyStart = new Vector2();\n\t\tconst dollyEnd = new Vector2();\n\t\tconst dollyDelta = new Vector2();\n\n\t\tconst dollyDirection = new Vector3();\n\t\tconst mouse = new Vector2();\n\t\tlet performCursorZoom = false;\n\n\t\tconst pointers = [];\n\t\tconst pointerPositions = {};\n\n\t\tlet controlActive = false;\n\n\t\tfunction getAutoRotationAngle( deltaTime ) {\n\n\t\t\tif ( deltaTime !== null ) {\n\n\t\t\t\treturn ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime;\n\n\t\t\t} else {\n\n\t\t\t\treturn 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getZoomScale( delta ) {\n\n\t\t\tconst normalizedDelta = Math.abs( delta * 0.01 );\n\t\t\treturn Math.pow( 0.95, scope.zoomSpeed * normalizedDelta );\n\n\t\t}\n\n\t\tfunction rotateLeft( angle ) {\n\n\t\t\tsphericalDelta.theta -= angle;\n\n\t\t}\n\n\t\tfunction rotateUp( angle ) {\n\n\t\t\tsphericalDelta.phi -= angle;\n\n\t\t}\n\n\t\tconst panLeft = function () {\n\n\t\t\tconst v = new Vector3();\n\n\t\t\treturn function panLeft( distance, objectMatrix ) {\n\n\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix\n\t\t\t\tv.multiplyScalar( - distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\tconst panUp = function () {\n\n\t\t\tconst v = new Vector3();\n\n\t\t\treturn function panUp( distance, objectMatrix ) {\n\n\t\t\t\tif ( scope.screenSpacePanning === true ) {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 1 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 );\n\t\t\t\t\tv.crossVectors( scope.object.up, v );\n\n\t\t\t\t}\n\n\t\t\t\tv.multiplyScalar( distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\t// deltaX and deltaY are in pixels; right and down are positive\n\t\tconst pan = function () {\n\n\t\t\tconst offset = new Vector3();\n\n\t\t\treturn function pan( deltaX, deltaY ) {\n\n\t\t\t\tconst element = scope.domElement;\n\n\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t// perspective\n\t\t\t\t\tconst position = scope.object.position;\n\t\t\t\t\toffset.copy( position ).sub( scope.target );\n\t\t\t\t\tlet targetDistance = offset.length();\n\n\t\t\t\t\t// half of the fov is center to top of screen\n\t\t\t\t\ttargetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );\n\n\t\t\t\t\t// we use only clientHeight here so aspect ratio does not distort speed\n\t\t\t\t\tpanLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );\n\t\t\t\t\tpanUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t// orthographic\n\t\t\t\t\tpanLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );\n\t\t\t\t\tpanUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// camera neither orthographic nor perspective\n\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );\n\t\t\t\t\tscope.enablePan = false;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}();\n\n\t\tfunction dollyOut( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale /= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction dollyIn( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale *= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction updateZoomParameters( x, y ) {\n\n\t\t\tif ( ! scope.zoomToCursor ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tperformCursorZoom = true;\n\n\t\t\tconst rect = scope.domElement.getBoundingClientRect();\n\t\t\tconst dx = x - rect.left;\n\t\t\tconst dy = y - rect.top;\n\t\t\tconst w = rect.width;\n\t\t\tconst h = rect.height;\n\n\t\t\tmouse.x = ( dx / w ) * 2 - 1;\n\t\t\tmouse.y = - ( dy / h ) * 2 + 1;\n\n\t\t\tdollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize();\n\n\t\t}\n\n\t\tfunction clampDistance( dist ) {\n\n\t\t\treturn Math.max( scope.minDistance, Math.min( scope.maxDistance, dist ) );\n\n\t\t}\n\n\t\t//\n\t\t// event callbacks - update the object state\n\t\t//\n\n\t\tfunction handleMouseDownRotate( event ) {\n\n\t\t\trotateStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownDolly( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientX );\n\t\t\tdollyStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownPan( event ) {\n\n\t\t\tpanStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseMoveRotate( event ) {\n\n\t\t\trotateEnd.set( event.clientX, event.clientY );\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMoveDolly( event ) {\n\n\t\t\tdollyEnd.set( event.clientX, event.clientY );\n\n\t\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( dollyDelta.y ) );\n\n\t\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( dollyDelta.y ) );\n\n\t\t\t}\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMovePan( event ) {\n\n\t\t\tpanEnd.set( event.clientX, event.clientY );\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseWheel( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientY );\n\n\t\t\tif ( event.deltaY < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( event.deltaY ) );\n\n\t\t\t} else if ( event.deltaY > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( event.deltaY ) );\n\n\t\t\t}\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleKeyDown( event ) {\n\n\t\t\tlet needsUpdate = false;\n\n\t\t\tswitch ( event.code ) {\n\n\t\t\t\tcase scope.keys.UP:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.BOTTOM:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, - scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.LEFT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.RIGHT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( - scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( needsUpdate ) {\n\n\t\t\t\t// prevent the browser from scrolling on cursor keys\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\tscope.update();\n\n\t\t\t}\n\n\n\t\t}\n\n\t\tfunction handleTouchStartRotate( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\trotateStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartPan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyStart.set( 0, distance );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchStartPan( event );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchStartRotate( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveRotate( event ) {\n\n\t\t\tif ( pointers.length == 1 ) {\n\n\t\t\t\trotateEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMovePan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyEnd.set( 0, distance );\n\n\t\t\tdollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );\n\n\t\t\tdollyOut( dollyDelta.y );\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tconst centerX = ( event.pageX + position.x ) * 0.5;\n\t\t\tconst centerY = ( event.pageY + position.y ) * 0.5;\n\n\t\t\tupdateZoomParameters( centerX, centerY );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchMovePan( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchMoveRotate( event );\n\n\t\t}\n\n\t\t//\n\t\t// event handlers - FSM: listen for events and reset state\n\t\t//\n\n\t\tfunction onPointerDown( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( pointers.length === 0 ) {\n\n\t\t\t\tscope.domElement.setPointerCapture( event.pointerId );\n\n\t\t\t\tscope.domElement.addEventListener( 'pointermove', onPointerMove );\n\t\t\t\tscope.domElement.addEventListener( 'pointerup', onPointerUp );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\taddPointer( event );\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchStart( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseDown( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerMove( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchMove( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseMove( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerUp( event ) {\n\n\t\t\tremovePointer( event );\n\n\t\t\tif ( pointers.length === 0 ) {\n\n\t\t\t\tscope.domElement.releasePointerCapture( event.pointerId );\n\n\t\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\t\t\t}\n\n\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t\tstate = STATE.NONE;\n\n\t\t}\n\n\t\tfunction onMouseDown( event ) {\n\n\t\t\tlet mouseAction;\n\n\t\t\tswitch ( event.button ) {\n\n\t\t\t\tcase 0:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.LEFT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.MIDDLE;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.RIGHT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tmouseAction = - 1;\n\n\t\t\t}\n\n\t\t\tswitch ( mouseAction ) {\n\n\t\t\t\tcase MOUSE.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseDownDolly( event );\n\n\t\t\t\t\tstate = STATE.DOLLY;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MOUSE.ROTATE:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MOUSE.PAN:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseMove( event ) {\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleMouseMoveRotate( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseMoveDolly( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleMouseMovePan( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseWheel( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\thandleMouseWheel( customWheelEvent( event ) );\n\n\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t}\n\n\t\tfunction customWheelEvent( event ) {\n\n\t\t\tconst mode = event.deltaMode;\n\n\t\t\t// minimal wheel event altered to meet delta-zoom demand\n\t\t\tconst newEvent = {\n\t\t\t\tclientX: event.clientX,\n\t\t\t\tclientY: event.clientY,\n\t\t\t\tdeltaY: event.deltaY,\n\t\t\t}\n\n\t\t\tswitch ( mode ) {\n\n\t\t\t\tcase 1: // LINE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 16;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2: // PAGE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 100;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\t// detect if event was triggered by pinching\n\t\t\tif ( event.ctrlKey && !controlActive ) {\n\n\t\t\t\tnewEvent.deltaY *= 10;\n\n\t\t\t}\n\n\t\t\treturn newEvent;\n\n\t\t}\n\n\t\tfunction interceptControlDown( event ) {\n\n\t\t\tif ( event.key === \"Control\" ) {\n\n\t\t\t\tcontrolActive = true;\n\t\t\t\t\n\t\t\t\tdocument.addEventListener('keyup', interceptControlUp, { passive: true, capture: true });\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction interceptControlUp( event ) {\n\n\t\t\tif ( event.key === \"Control\" ) {\n\n\t\t\t\tcontrolActive = false;\n\t\t\t\t\n\t\t\t\tdocument.removeEventListener('keyup', interceptControlUp, { passive: true, capture: true });\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onKeyDown( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enablePan === false ) return;\n\n\t\t\thandleKeyDown( event );\n\n\t\t}\n\n\t\tfunction onTouchStart( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( pointers.length ) {\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tswitch ( scope.touches.ONE ) {\n\n\t\t\t\t\t\tcase TOUCH.ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase TOUCH.PAN:\n\n\t\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tswitch ( scope.touches.TWO ) {\n\n\t\t\t\t\t\tcase TOUCH.DOLLY_PAN:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase TOUCH.DOLLY_ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onTouchMove( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.TOUCH_ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMovePan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_PAN:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyPan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_ROTATE:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onContextMenu( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t}\n\n\t\tfunction addPointer( event ) {\n\n\t\t\tpointers.push( event.pointerId );\n\n\t\t}\n\n\t\tfunction removePointer( event ) {\n\n\t\t\tdelete pointerPositions[ event.pointerId ];\n\n\t\t\tfor ( let i = 0; i < pointers.length; i ++ ) {\n\n\t\t\t\tif ( pointers[ i ] == event.pointerId ) {\n\n\t\t\t\t\tpointers.splice( i, 1 );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction trackPointer( event ) {\n\n\t\t\tlet position = pointerPositions[ event.pointerId ];\n\n\t\t\tif ( position === undefined ) {\n\n\t\t\t\tposition = new Vector2();\n\t\t\t\tpointerPositions[ event.pointerId ] = position;\n\n\t\t\t}\n\n\t\t\tposition.set( event.pageX, event.pageY );\n\n\t\t}\n\n\t\tfunction getSecondPointerPosition( event ) {\n\n\t\t\tconst pointerId = ( event.pointerId === pointers[ 0 ] ) ? pointers[ 1 ] : pointers[ 0 ];\n\n\t\t\treturn pointerPositions[ pointerId ];\n\n\t\t}\n\n\t\t//\n\n\t\tscope.domElement.addEventListener( 'contextmenu', onContextMenu );\n\n\t\tscope.domElement.addEventListener( 'pointerdown', onPointerDown );\n\t\tscope.domElement.addEventListener( 'pointercancel', onPointerUp );\n\t\tscope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } );\n\n\t\tdocument.addEventListener( 'keydown', interceptControlDown, { passive: true, capture: true } );\n\n\t\t// force an update at start\n\n\t\tthis.update();\n\n\t}\n\n}\n\nexport { OrbitControls };","import * as THREE from 'three';\nimport { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';\nimport type { ForceGraph3DOptions, Vector3Data } from '../utils/types';\nimport { getContainerDimensions } from '../utils/ContainerManager';\n\n/**\n * Scene Manager\n * Handles Three.js scene setup, camera, renderer, and controls\n */\nexport class SceneManager {\n public scene: THREE.Scene;\n public camera: THREE.PerspectiveCamera;\n public renderer: THREE.WebGLRenderer;\n public controls: OrbitControls;\n\n private container: HTMLElement;\n private resizeHandler: () => void;\n\n constructor(container: HTMLElement, options: ForceGraph3DOptions) {\n this.container = container;\n\n // Create scene\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(\n options.backgroundColor ?? 0x0a0a0a\n );\n\n // Create camera\n const { width, height } = getContainerDimensions(container);\n const fov = options.cameraFov ?? 75;\n this.camera = new THREE.PerspectiveCamera(fov, width / height, 0.1, 2000);\n\n const camPos = options.cameraPosition ?? { x: 0, y: 0, z: 80 };\n this.camera.position.set(camPos.x, camPos.y, camPos.z);\n\n // Create renderer with high quality settings\n this.renderer = new THREE.WebGLRenderer({\n antialias: true,\n alpha: true,\n powerPreference: 'high-performance',\n });\n this.renderer.setSize(width, height);\n this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));\n this.renderer.toneMapping = THREE.ACESFilmicToneMapping;\n this.renderer.toneMappingExposure = 1.0;\n this.renderer.shadowMap.enabled = true;\n this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;\n\n container.appendChild(this.renderer.domElement);\n\n // Create orbit controls\n this.controls = new OrbitControls(this.camera, this.renderer.domElement);\n this.controls.enableDamping = true;\n this.controls.dampingFactor = 0.05;\n this.controls.rotateSpeed = 0.8;\n this.controls.zoomSpeed = 1.2;\n this.controls.minDistance = 10;\n this.controls.maxDistance = 2000;\n\n // Setup lighting\n this.setupLighting();\n\n // Handle resize\n this.resizeHandler = this.onWindowResize.bind(this);\n window.addEventListener('resize', this.resizeHandler);\n }\n\n /**\n * Sets up scene lighting for gradient glass on dark background\n */\n private setupLighting(): void {\n // Moderate ambient light for dark environment\n const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);\n this.scene.add(ambientLight);\n\n // Main key light from top-right\n const keyLight = new THREE.DirectionalLight(0xffffff, 0.9);\n keyLight.position.set(50, 60, 40);\n keyLight.castShadow = true;\n keyLight.shadow.mapSize.width = 1024;\n keyLight.shadow.mapSize.height = 1024;\n this.scene.add(keyLight);\n\n // Fill light from opposite side\n const fillLight = new THREE.DirectionalLight(0xfff0e0, 0.4);\n fillLight.position.set(-50, 30, -40);\n this.scene.add(fillLight);\n\n // Rim light for edge highlights\n const rimLight = new THREE.DirectionalLight(0xffffff, 0.3);\n rimLight.position.set(0, -30, -50);\n this.scene.add(rimLight);\n\n // Tangerine accent light\n const accentLight1 = new THREE.PointLight(0xff9966, 0.5, 150);\n accentLight1.position.set(40, 20, 40);\n this.scene.add(accentLight1);\n\n // Warm accent light\n const accentLight2 = new THREE.PointLight(0xffcc99, 0.4, 150);\n accentLight2.position.set(-40, -20, 40);\n this.scene.add(accentLight2);\n\n // Cool blue accent for contrast\n const accentLight3 = new THREE.PointLight(0x6699ff, 0.2, 100);\n accentLight3.position.set(0, 40, -40);\n this.scene.add(accentLight3);\n }\n\n /**\n * Handle window resize\n */\n private onWindowResize(): void {\n const { width, height } = getContainerDimensions(this.container);\n\n this.camera.aspect = width / height;\n this.camera.updateProjectionMatrix();\n\n this.renderer.setSize(width, height);\n }\n\n /**\n * Adds an object to the scene\n */\n add(object: THREE.Object3D): void {\n this.scene.add(object);\n }\n\n /**\n * Removes an object from the scene\n */\n remove(object: THREE.Object3D): void {\n this.scene.remove(object);\n }\n\n /**\n * Renders the scene\n */\n render(): void {\n this.controls.update();\n this.renderer.render(this.scene, this.camera);\n }\n\n /**\n * Gets the camera position\n */\n getCameraPosition(): Vector3Data {\n return {\n x: this.camera.position.x,\n y: this.camera.position.y,\n z: this.camera.position.z,\n };\n }\n\n /**\n * Gets the camera's forward direction\n */\n getCameraDirection(): THREE.Vector3 {\n const direction = new THREE.Vector3();\n this.camera.getWorldDirection(direction);\n return direction;\n }\n\n /**\n * Dispose all resources\n */\n dispose(): void {\n window.removeEventListener('resize', this.resizeHandler);\n\n this.controls.dispose();\n this.renderer.dispose();\n\n // Remove renderer element\n if (this.renderer.domElement.parentNode) {\n this.renderer.domElement.parentNode.removeChild(this.renderer.domElement);\n }\n\n // Clear scene\n while (this.scene.children.length > 0) {\n const child = this.scene.children[0];\n this.scene.remove(child);\n }\n }\n}\n","import * as THREE from 'three';\nimport { SceneManager } from './SceneManager';\nimport { NodeFactory } from '../factory/NodeFactory';\nimport type {\n NodeData,\n InternalNode,\n NodeObject,\n Vector3Data,\n LODLevel\n} from '../utils/types';\nimport { validateNodeData } from '../utils/validation';\n\n/**\n * Node Manager\n * Handles node CRUD operations and position updates\n */\nexport class NodeManager {\n private sceneManager: SceneManager;\n private nodeFactory: NodeFactory;\n\n private nodes: Map<string, InternalNode> = new Map();\n private nodeObjects: Map<string, NodeObject> = new Map();\n\n constructor(sceneManager: SceneManager, nodeFactory: NodeFactory) {\n this.sceneManager = sceneManager;\n this.nodeFactory = nodeFactory;\n }\n\n /**\n * Checks if a node exists\n */\n hasNode(nodeId: string): boolean {\n return this.nodes.has(nodeId);\n }\n\n // Scale spawn volume with expected graph size\n private static expectedNodeCount: number = 100;\n\n /**\n * Sets the expected total node count so spawn positions can be scaled.\n * Call this before adding nodes in bulk.\n */\n static setExpectedNodeCount(count: number): void {\n NodeManager.expectedNodeCount = count;\n }\n\n /**\n * Adds a node to the graph\n * @returns true if added, false if node already exists or invalid\n */\n addNode(nodeData: NodeData, lodLevel: LODLevel = 0): boolean {\n // Validate input\n if (!validateNodeData(nodeData)) {\n return false;\n }\n\n // Check for duplicate\n if (this.nodes.has(nodeData.id)) {\n console.warn(`[ForceGraph3D] Node with id \"${nodeData.id}\" already exists`);\n return false;\n }\n\n // Scale spawn volume with node count (cube-root scaling)\n const spread = Math.max(50, Math.cbrt(NodeManager.expectedNodeCount) * 10);\n\n // Generate random position if not provided\n const position: Vector3Data = nodeData.position ?? {\n x: (Math.random() - 0.5) * spread,\n y: (Math.random() - 0.5) * spread,\n z: (Math.random() - 0.5) * spread,\n };\n\n // Create internal node with physics state\n const internalNode: InternalNode = {\n ...nodeData,\n position,\n velocity: { x: 0, y: 0, z: 0 },\n mass: 1,\n };\n\n // Create visual representation\n const nodeObject = this.nodeFactory.createNode(\n { ...nodeData, position },\n lodLevel\n );\n\n // Add to scene\n this.sceneManager.add(nodeObject.group);\n\n // Store references\n this.nodes.set(nodeData.id, internalNode);\n this.nodeObjects.set(nodeData.id, nodeObject);\n\n return true;\n }\n\n /**\n * Removes a node from the graph\n * @returns true if removed, false if not found\n */\n removeNode(nodeId: string): boolean {\n const node = this.nodes.get(nodeId);\n const nodeObject = this.nodeObjects.get(nodeId);\n\n if (!node || !nodeObject) {\n return false;\n }\n\n // Remove from scene\n this.sceneManager.remove(nodeObject.group);\n\n // Dispose resources\n this.nodeFactory.disposeNode(nodeObject);\n\n // Remove from maps\n this.nodes.delete(nodeId);\n this.nodeObjects.delete(nodeId);\n\n return true;\n }\n\n /**\n * Updates a node's properties\n */\n updateNode(nodeId: string, updates: Partial<NodeData>): boolean {\n const node = this.nodes.get(nodeId);\n const nodeObject = this.nodeObjects.get(nodeId);\n\n if (!node || !nodeObject) {\n console.warn(`[ForceGraph3D] Node \"${nodeId}\" not found`);\n return false;\n }\n\n // Update internal node data\n if (updates.label !== undefined) {\n node.label = updates.label;\n this.nodeFactory.updateNodeLabel(nodeObject, updates.label);\n }\n\n if (updates.color !== undefined) {\n node.color = updates.color;\n this.nodeFactory.updateNodeColor(nodeObject, updates.color);\n }\n\n // Store any additional custom data\n Object.keys(updates).forEach(key => {\n if (key !== 'id' && key !== 'label' && key !== 'color' && key !== 'position') {\n (node as Record<string, unknown>)[key] = updates[key as keyof NodeData];\n }\n });\n\n return true;\n }\n\n /**\n * Updates a node's position (called by physics engine)\n */\n updateNodePosition(nodeId: string, position: Vector3Data): void {\n const node = this.nodes.get(nodeId);\n const nodeObject = this.nodeObjects.get(nodeId);\n\n if (node && nodeObject) {\n node.position = position;\n nodeObject.group.position.set(position.x, position.y, position.z);\n }\n }\n\n /**\n * Updates a node's LOD level\n */\n updateNodeLOD(nodeId: string, lodLevel: LODLevel): void {\n const nodeObject = this.nodeObjects.get(nodeId);\n if (nodeObject) {\n this.nodeFactory.updateNodeLOD(nodeObject, lodLevel);\n }\n }\n\n /**\n * Gets a node by ID\n */\n getNode(nodeId: string): InternalNode | undefined {\n return this.nodes.get(nodeId);\n }\n\n /**\n * Gets a node's visual object\n */\n getNodeObject(nodeId: string): NodeObject | undefined {\n return this.nodeObjects.get(nodeId);\n }\n\n /**\n * Gets all nodes\n */\n getAllNodes(): Map<string, InternalNode> {\n return this.nodes;\n }\n\n /**\n * Gets all node objects (for raycasting)\n */\n getAllNodeObjects(): THREE.Object3D[] {\n const objects: THREE.Object3D[] = [];\n this.nodeObjects.forEach(nodeObject => {\n objects.push(nodeObject.group);\n });\n return objects;\n }\n\n /**\n * Gets all spheres (for raycasting)\n */\n getAllSpheres(): THREE.Mesh[] {\n const spheres: THREE.Mesh[] = [];\n this.nodeObjects.forEach(nodeObject => {\n spheres.push(nodeObject.sphere);\n });\n return spheres;\n }\n\n /**\n * Gets node count\n */\n getNodeCount(): number {\n return this.nodes.size;\n }\n\n /**\n * Clears all nodes\n */\n clear(): void {\n this.nodes.forEach((_, nodeId) => {\n this.removeNode(nodeId);\n });\n }\n\n /**\n * Dispose resources\n */\n dispose(): void {\n this.clear();\n }\n}\n","import * as THREE from 'three';\nimport { SceneManager } from './SceneManager';\nimport { NodeManager } from './NodeManager';\nimport { EdgeFactory } from '../factory/EdgeFactory';\nimport type { Edge, EdgeObject } from '../utils/types';\nimport { validateEdgeData, createEdgeKey } from '../utils/validation';\n\n/**\n * Edge Manager\n * Handles edge CRUD operations, position updates, and highlighting\n */\nexport class EdgeManager {\n private sceneManager: SceneManager;\n private nodeManager: NodeManager;\n private edgeFactory: EdgeFactory;\n\n private edges: Edge[] = [];\n private edgeObjects: EdgeObject[] = [];\n private edgeKeySet: Set<string> = new Set();\n private highlightedEdgeKey: string | null = null;\n\n constructor(\n sceneManager: SceneManager,\n nodeManager: NodeManager,\n edgeFactory: EdgeFactory\n ) {\n this.sceneManager = sceneManager;\n this.nodeManager = nodeManager;\n this.edgeFactory = edgeFactory;\n }\n\n /**\n * Checks if an edge exists\n */\n hasEdge(source: string, target: string): boolean {\n const key = createEdgeKey(source, target);\n return this.edgeKeySet.has(key);\n }\n\n /**\n * Adds an edge to the graph\n * @returns true if added, false if edge already exists or nodes don't exist\n */\n addEdge(edgeData: Edge): boolean {\n // Validate input\n if (!validateEdgeData(edgeData)) {\n return false;\n }\n\n // Check if source and target nodes exist\n if (!this.nodeManager.hasNode(edgeData.source)) {\n console.warn(`[ForceGraph3D] Source node \"${edgeData.source}\" does not exist`);\n return false;\n }\n\n if (!this.nodeManager.hasNode(edgeData.target)) {\n console.warn(`[ForceGraph3D] Target node \"${edgeData.target}\" does not exist`);\n return false;\n }\n\n // Check for duplicate edge (bidirectional check)\n const edgeKey = createEdgeKey(edgeData.source, edgeData.target);\n if (this.edgeKeySet.has(edgeKey)) {\n console.warn(`[ForceGraph3D] Edge \"${edgeData.source}\" -> \"${edgeData.target}\" already exists`);\n return false;\n }\n\n // Get node data\n const sourceNode = this.nodeManager.getNode(edgeData.source)!;\n const targetNode = this.nodeManager.getNode(edgeData.target)!;\n\n // Create visual representation with full node data\n const edgeObject = this.edgeFactory.createEdge(\n edgeData,\n sourceNode,\n targetNode,\n sourceNode.position,\n targetNode.position\n );\n\n // Add to scene\n this.sceneManager.add(edgeObject.line);\n\n // Store references\n this.edges.push(edgeData);\n this.edgeObjects.push(edgeObject);\n this.edgeKeySet.add(edgeKey);\n\n return true;\n }\n\n /**\n * Removes an edge from the graph\n * @returns true if removed, false if not found\n */\n removeEdge(source: string, target: string): boolean {\n const edgeKey = createEdgeKey(source, target);\n\n if (!this.edgeKeySet.has(edgeKey)) {\n return false;\n }\n\n // Find and remove the edge\n const index = this.edges.findIndex(e =>\n createEdgeKey(e.source, e.target) === edgeKey\n );\n\n if (index === -1) {\n return false;\n }\n\n const edgeObject = this.edgeObjects[index];\n\n // Remove from scene\n this.sceneManager.remove(edgeObject.line);\n\n // Dispose resources\n this.edgeFactory.disposeEdge(edgeObject);\n\n // Remove from arrays and set\n this.edges.splice(index, 1);\n this.edgeObjects.splice(index, 1);\n this.edgeKeySet.delete(edgeKey);\n\n // Clear highlight if this was the highlighted edge\n if (this.highlightedEdgeKey === edgeKey) {\n this.highlightedEdgeKey = null;\n }\n\n return true;\n }\n\n /**\n * Highlights an edge\n */\n highlightEdge(source: string, target: string): void {\n const edgeKey = createEdgeKey(source, target);\n\n // Unhighlight previous edge if different\n if (this.highlightedEdgeKey && this.highlightedEdgeKey !== edgeKey) {\n this.unhighlightCurrentEdge();\n }\n\n // Find and highlight the edge\n const index = this.edges.findIndex(e =>\n createEdgeKey(e.source, e.target) === edgeKey\n );\n\n if (index !== -1) {\n this.edgeFactory.highlightEdge(this.edgeObjects[index]);\n this.highlightedEdgeKey = edgeKey;\n }\n }\n\n /**\n * Unhighlights the currently highlighted edge\n */\n unhighlightCurrentEdge(): void {\n if (!this.highlightedEdgeKey) return;\n\n const index = this.edges.findIndex(e =>\n createEdgeKey(e.source, e.target) === this.highlightedEdgeKey\n );\n\n if (index !== -1) {\n this.edgeFactory.unhighlightEdge(this.edgeObjects[index]);\n }\n\n this.highlightedEdgeKey = null;\n }\n\n /**\n * Removes all edges connected to a node\n */\n removeEdgesForNode(nodeId: string): void {\n // Find all edges connected to this node\n const edgesToRemove: Array<{ source: string; target: string }> = [];\n\n this.edges.forEach(edge => {\n if (edge.source === nodeId || edge.target === nodeId) {\n edgesToRemove.push({ source: edge.source, target: edge.target });\n }\n });\n\n // Remove each edge\n edgesToRemove.forEach(edge => {\n this.removeEdge(edge.source, edge.target);\n });\n }\n\n /**\n * Gets all edges for a node\n */\n getEdgesForNode(nodeId: string): Edge[] {\n return this.edges.filter(e => e.source === nodeId || e.target === nodeId);\n }\n\n /**\n * Gets neighbor node IDs for a node\n */\n getNeighborIds(nodeId: string): string[] {\n const neighbors: string[] = [];\n\n this.edges.forEach(edge => {\n if (edge.source === nodeId) {\n neighbors.push(edge.target);\n } else if (edge.target === nodeId) {\n neighbors.push(edge.source);\n }\n });\n\n return [...new Set(neighbors)]; // Remove duplicates\n }\n\n /**\n * Updates all edge positions based on current node positions\n */\n updateEdgePositions(): void {\n this.edgeObjects.forEach((edgeObject, index) => {\n const edge = this.edges[index];\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n\n if (sourceNode && targetNode) {\n this.edgeFactory.updateEdgePositions(\n edgeObject,\n sourceNode.position,\n targetNode.position\n );\n }\n });\n }\n\n /**\n * Gets all edges\n */\n getAllEdges(): Edge[] {\n return this.edges;\n }\n\n /**\n * Gets all edge line objects (for raycasting)\n */\n getAllEdgeLines(): THREE.Line[] {\n return this.edgeObjects.map(eo => eo.line);\n }\n\n /**\n * Gets edge count\n */\n getEdgeCount(): number {\n return this.edges.length;\n }\n\n /**\n * Clears all edges\n */\n clear(): void {\n // Remove all edges from scene and dispose\n this.edgeObjects.forEach(edgeObject => {\n this.sceneManager.remove(edgeObject.line);\n this.edgeFactory.disposeEdge(edgeObject);\n });\n\n this.edges = [];\n this.edgeObjects = [];\n this.edgeKeySet.clear();\n this.highlightedEdgeKey = null;\n }\n\n /**\n * Dispose resources\n */\n dispose(): void {\n this.clear();\n }\n}\n","import type { InternalNode, Edge, Vector3Data } from '../utils/types';\n\n/**\n * Graph Engine\n * Force-directed physics simulation with Barnes-Hut optimization\n * Supports graphs up to 10,000+ nodes via adaptive force scaling\n */\nexport class GraphEngine {\n private nodes: Map<string, InternalNode>;\n private edges: Edge[];\n\n // Physics parameters\n private repulsionStrength: number;\n private attractionStrength: number;\n private damping: number;\n private useBarnesHut: boolean;\n private barnesHutTheta: number;\n\n // Scaling safeguards\n private readonly MAX_VELOCITY = 5; // Max units/step\n private readonly REPULSION_CUTOFF = 200; // Skip repulsion beyond this distance\n private readonly REPULSION_CUTOFF_SQ: number; // Precomputed cutoff²\n private readonly GRAVITY_STRENGTH = 0.02; // Centering force strength\n\n // Simulation state\n private alpha: number = 1;\n private alphaDecay: number = 0.0228;\n private alphaMin: number = 0.001;\n private alphaTarget: number = 0;\n\n constructor(\n nodes: Map<string, InternalNode>,\n edges: Edge[],\n options: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n useBarnesHut?: boolean;\n barnesHutTheta?: number;\n } = {}\n ) {\n this.nodes = nodes;\n this.edges = edges;\n\n this.repulsionStrength = options.repulsionStrength ?? 100;\n this.attractionStrength = options.attractionStrength ?? 0.01;\n this.damping = options.damping ?? 0.9;\n this.useBarnesHut = options.useBarnesHut ?? false;\n this.barnesHutTheta = options.barnesHutTheta ?? 0.5;\n\n this.REPULSION_CUTOFF_SQ = this.REPULSION_CUTOFF * this.REPULSION_CUTOFF;\n }\n\n /**\n * Computes effective repulsion strength scaled by node count.\n * This keeps total repulsion energy bounded as N grows.\n */\n private getEffectiveRepulsion(): number {\n const n = this.nodes.size;\n if (n <= 500) return this.repulsionStrength;\n // Scale inversely with sqrt(N) for large graphs\n return this.repulsionStrength * Math.sqrt(500) / Math.sqrt(n);\n }\n\n /**\n * Runs one simulation step\n */\n simulate(): void {\n if (this.alpha < this.alphaMin) return;\n\n const nodeCount = this.nodes.size;\n\n // Auto-enable Barnes-Hut for large graphs\n const shouldUseBarnesHut = this.useBarnesHut || nodeCount >= 1000;\n\n // Calculate repulsion forces\n if (shouldUseBarnesHut && nodeCount >= 100) {\n this.calculateRepulsionBarnesHut();\n } else {\n this.calculateRepulsionBruteForce();\n }\n\n // Calculate attraction forces along edges\n this.calculateAttraction();\n\n // Apply centering gravity force\n this.applyCenteringForce();\n\n // Apply velocities and damping (with velocity capping)\n this.applyForces();\n\n // Decay alpha\n this.alpha += (this.alphaTarget - this.alpha) * this.alphaDecay;\n }\n\n /**\n * Brute force repulsion - O(n²)\n */\n private calculateRepulsionBruteForce(): void {\n const nodesArray = Array.from(this.nodes.values());\n const n = nodesArray.length;\n const effectiveRepulsion = this.getEffectiveRepulsion();\n\n for (let i = 0; i < n; i++) {\n const nodeA = nodesArray[i];\n\n for (let j = i + 1; j < n; j++) {\n const nodeB = nodesArray[j];\n\n const dx = nodeB.position.x - nodeA.position.x;\n const dy = nodeB.position.y - nodeA.position.y;\n const dz = nodeB.position.z - nodeA.position.z;\n\n let distSq = dx * dx + dy * dy + dz * dz;\n\n // Distance cutoff: skip pairs that are far apart\n if (distSq > this.REPULSION_CUTOFF_SQ) continue;\n\n if (distSq < 0.01) distSq = 0.01; // Prevent division by zero\n\n const dist = Math.sqrt(distSq);\n const force = (effectiveRepulsion * this.alpha) / distSq;\n\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n const fz = (dz / dist) * force;\n\n // Apply equal and opposite forces\n nodeA.velocity.x -= fx / nodeA.mass;\n nodeA.velocity.y -= fy / nodeA.mass;\n nodeA.velocity.z -= fz / nodeA.mass;\n\n nodeB.velocity.x += fx / nodeB.mass;\n nodeB.velocity.y += fy / nodeB.mass;\n nodeB.velocity.z += fz / nodeB.mass;\n }\n }\n }\n\n /**\n * Barnes-Hut approximation - O(n log n)\n */\n private calculateRepulsionBarnesHut(): void {\n const nodesArray = Array.from(this.nodes.values());\n\n // Build octree\n const octree = new Octree(nodesArray);\n\n // Calculate forces using octree\n for (const node of nodesArray) {\n this.calculateForceFromOctree(node, octree.root);\n }\n }\n\n /**\n * Recursive force calculation using octree\n */\n private calculateForceFromOctree(node: InternalNode, octreeNode: OctreeNode): void {\n if (octreeNode.isLeaf) {\n if (octreeNode.node && octreeNode.node.id !== node.id) {\n this.applyRepulsionBetween(node, octreeNode.node);\n }\n return;\n }\n\n if (octreeNode.mass === 0) return;\n\n const dx = octreeNode.centerOfMass.x - node.position.x;\n const dy = octreeNode.centerOfMass.y - node.position.y;\n const dz = octreeNode.centerOfMass.z - node.position.z;\n const distSq = dx * dx + dy * dy + dz * dz;\n\n // Distance cutoff for entire octree cell\n if (distSq > this.REPULSION_CUTOFF_SQ) return;\n\n const dist = Math.sqrt(distSq);\n const effectiveRepulsion = this.getEffectiveRepulsion();\n\n // Check if we can use the approximation\n if (dist > 0 && octreeNode.size / dist < this.barnesHutTheta) {\n // Treat as single body\n const safeDist = Math.max(distSq, 0.01);\n const force = (effectiveRepulsion * this.alpha * octreeNode.mass) / safeDist;\n\n node.velocity.x -= (dx / dist) * force / node.mass;\n node.velocity.y -= (dy / dist) * force / node.mass;\n node.velocity.z -= (dz / dist) * force / node.mass;\n } else {\n // Recurse into children\n for (const child of octreeNode.children) {\n if (child) {\n this.calculateForceFromOctree(node, child);\n }\n }\n }\n }\n\n /**\n * Apply repulsion between two nodes (with cutoff)\n */\n private applyRepulsionBetween(nodeA: InternalNode, nodeB: InternalNode): void {\n const dx = nodeB.position.x - nodeA.position.x;\n const dy = nodeB.position.y - nodeA.position.y;\n const dz = nodeB.position.z - nodeA.position.z;\n\n let distSq = dx * dx + dy * dy + dz * dz;\n\n // Distance cutoff\n if (distSq > this.REPULSION_CUTOFF_SQ) return;\n\n if (distSq < 0.01) distSq = 0.01;\n\n const dist = Math.sqrt(distSq);\n const effectiveRepulsion = this.getEffectiveRepulsion();\n const force = (effectiveRepulsion * this.alpha) / distSq;\n\n nodeA.velocity.x -= (dx / dist) * force / nodeA.mass;\n nodeA.velocity.y -= (dy / dist) * force / nodeA.mass;\n nodeA.velocity.z -= (dz / dist) * force / nodeA.mass;\n }\n\n /**\n * Calculate attraction forces along edges\n */\n private calculateAttraction(): void {\n const nodeCount = this.nodes.size;\n // Boost attraction for large graphs to counterbalance reduced repulsion\n const attractionMultiplier = nodeCount > 500 ? 1 + Math.log10(nodeCount / 500) : 1;\n\n for (const edge of this.edges) {\n const sourceNode = this.nodes.get(edge.source);\n const targetNode = this.nodes.get(edge.target);\n\n if (!sourceNode || !targetNode) continue;\n\n const dx = targetNode.position.x - sourceNode.position.x;\n const dy = targetNode.position.y - sourceNode.position.y;\n const dz = targetNode.position.z - sourceNode.position.z;\n\n const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);\n if (dist < 0.01) continue;\n\n // Spring-like attraction (Hooke's law)\n const targetDist = 15; // Ideal edge length\n const force = (dist - targetDist) * this.attractionStrength * attractionMultiplier * this.alpha;\n\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n const fz = (dz / dist) * force;\n\n sourceNode.velocity.x += fx / sourceNode.mass;\n sourceNode.velocity.y += fy / sourceNode.mass;\n sourceNode.velocity.z += fz / sourceNode.mass;\n\n targetNode.velocity.x -= fx / targetNode.mass;\n targetNode.velocity.y -= fy / targetNode.mass;\n targetNode.velocity.z -= fz / targetNode.mass;\n }\n }\n\n /**\n * Applies a weak centering/gravity force pulling all nodes toward origin.\n * Prevents the graph from drifting infinitely away from the center.\n */\n private applyCenteringForce(): void {\n const gravity = this.GRAVITY_STRENGTH * this.alpha;\n\n for (const node of this.nodes.values()) {\n node.velocity.x -= node.position.x * gravity;\n node.velocity.y -= node.position.y * gravity;\n node.velocity.z -= node.position.z * gravity;\n }\n }\n\n /**\n * Apply velocities and damping to positions, with velocity capping\n */\n private applyForces(): void {\n for (const node of this.nodes.values()) {\n // Apply damping\n node.velocity.x *= this.damping;\n node.velocity.y *= this.damping;\n node.velocity.z *= this.damping;\n\n // Cap velocity to prevent explosion\n const speed = Math.sqrt(\n node.velocity.x * node.velocity.x +\n node.velocity.y * node.velocity.y +\n node.velocity.z * node.velocity.z\n );\n if (speed > this.MAX_VELOCITY) {\n const scale = this.MAX_VELOCITY / speed;\n node.velocity.x *= scale;\n node.velocity.y *= scale;\n node.velocity.z *= scale;\n }\n\n // Update position\n node.position.x += node.velocity.x;\n node.position.y += node.velocity.y;\n node.position.z += node.velocity.z;\n }\n }\n\n /**\n * Updates the edges reference\n */\n setEdges(edges: Edge[]): void {\n this.edges = edges;\n }\n\n /**\n * Resets the simulation (restarts with full energy)\n */\n restart(): void {\n this.alpha = 1;\n }\n\n /**\n * Gets the current alpha value\n */\n getAlpha(): number {\n return this.alpha;\n }\n\n /**\n * Sets physics parameters\n */\n setPhysicsParams(params: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n }): void {\n if (params.repulsionStrength !== undefined) {\n this.repulsionStrength = params.repulsionStrength;\n }\n if (params.attractionStrength !== undefined) {\n this.attractionStrength = params.attractionStrength;\n }\n if (params.damping !== undefined) {\n this.damping = params.damping;\n }\n }\n}\n\n// ============================================================================\n// Octree Implementation for Barnes-Hut\n// ============================================================================\n\ninterface OctreeNode {\n bounds: { min: Vector3Data; max: Vector3Data };\n size: number;\n centerOfMass: Vector3Data;\n mass: number;\n isLeaf: boolean;\n node: InternalNode | null;\n children: (OctreeNode | null)[];\n}\n\nclass Octree {\n root: OctreeNode;\n\n constructor(nodes: InternalNode[]) {\n // Calculate bounding box\n const bounds = this.calculateBounds(nodes);\n this.root = this.buildTree(nodes, bounds);\n }\n\n private calculateBounds(nodes: InternalNode[]): { min: Vector3Data; max: Vector3Data } {\n if (nodes.length === 0) {\n return {\n min: { x: -100, y: -100, z: -100 },\n max: { x: 100, y: 100, z: 100 },\n };\n }\n\n const min = { x: Infinity, y: Infinity, z: Infinity };\n const max = { x: -Infinity, y: -Infinity, z: -Infinity };\n\n for (const node of nodes) {\n min.x = Math.min(min.x, node.position.x);\n min.y = Math.min(min.y, node.position.y);\n min.z = Math.min(min.z, node.position.z);\n max.x = Math.max(max.x, node.position.x);\n max.y = Math.max(max.y, node.position.y);\n max.z = Math.max(max.z, node.position.z);\n }\n\n // Add padding\n const padding = 10;\n min.x -= padding; min.y -= padding; min.z -= padding;\n max.x += padding; max.y += padding; max.z += padding;\n\n return { min, max };\n }\n\n private buildTree(\n nodes: InternalNode[],\n bounds: { min: Vector3Data; max: Vector3Data },\n depth: number = 0\n ): OctreeNode {\n const size = Math.max(\n bounds.max.x - bounds.min.x,\n bounds.max.y - bounds.min.y,\n bounds.max.z - bounds.min.z\n );\n\n // Base case: empty or single node\n if (nodes.length === 0) {\n return {\n bounds,\n size,\n centerOfMass: { x: 0, y: 0, z: 0 },\n mass: 0,\n isLeaf: true,\n node: null,\n children: [],\n };\n }\n\n if (nodes.length === 1 || depth > 20) {\n // Calculate center of mass\n let totalMass = 0;\n const com = { x: 0, y: 0, z: 0 };\n\n for (const node of nodes) {\n totalMass += node.mass;\n com.x += node.position.x * node.mass;\n com.y += node.position.y * node.mass;\n com.z += node.position.z * node.mass;\n }\n\n if (totalMass > 0) {\n com.x /= totalMass;\n com.y /= totalMass;\n com.z /= totalMass;\n }\n\n return {\n bounds,\n size,\n centerOfMass: com,\n mass: totalMass,\n isLeaf: true,\n node: nodes[0],\n children: [],\n };\n }\n\n // Divide into 8 octants\n const midX = (bounds.min.x + bounds.max.x) / 2;\n const midY = (bounds.min.y + bounds.max.y) / 2;\n const midZ = (bounds.min.z + bounds.max.z) / 2;\n\n const octants: InternalNode[][] = [[], [], [], [], [], [], [], []];\n\n for (const node of nodes) {\n const idx =\n (node.position.x >= midX ? 1 : 0) +\n (node.position.y >= midY ? 2 : 0) +\n (node.position.z >= midZ ? 4 : 0);\n octants[idx].push(node);\n }\n\n const childBounds: Array<{ min: Vector3Data; max: Vector3Data }> = [\n { min: { x: bounds.min.x, y: bounds.min.y, z: bounds.min.z }, max: { x: midX, y: midY, z: midZ } },\n { min: { x: midX, y: bounds.min.y, z: bounds.min.z }, max: { x: bounds.max.x, y: midY, z: midZ } },\n { min: { x: bounds.min.x, y: midY, z: bounds.min.z }, max: { x: midX, y: bounds.max.y, z: midZ } },\n { min: { x: midX, y: midY, z: bounds.min.z }, max: { x: bounds.max.x, y: bounds.max.y, z: midZ } },\n { min: { x: bounds.min.x, y: bounds.min.y, z: midZ }, max: { x: midX, y: midY, z: bounds.max.z } },\n { min: { x: midX, y: bounds.min.y, z: midZ }, max: { x: bounds.max.x, y: midY, z: bounds.max.z } },\n { min: { x: bounds.min.x, y: midY, z: midZ }, max: { x: midX, y: bounds.max.y, z: bounds.max.z } },\n { min: { x: midX, y: midY, z: midZ }, max: { x: bounds.max.x, y: bounds.max.y, z: bounds.max.z } },\n ];\n\n const children: (OctreeNode | null)[] = [];\n let totalMass = 0;\n const com = { x: 0, y: 0, z: 0 };\n\n for (let i = 0; i < 8; i++) {\n if (octants[i].length > 0) {\n const child = this.buildTree(octants[i], childBounds[i], depth + 1);\n children.push(child);\n\n totalMass += child.mass;\n com.x += child.centerOfMass.x * child.mass;\n com.y += child.centerOfMass.y * child.mass;\n com.z += child.centerOfMass.z * child.mass;\n } else {\n children.push(null);\n }\n }\n\n if (totalMass > 0) {\n com.x /= totalMass;\n com.y /= totalMass;\n com.z /= totalMass;\n }\n\n return {\n bounds,\n size,\n centerOfMass: com,\n mass: totalMass,\n isLeaf: false,\n node: null,\n children,\n };\n }\n}\n","import { SceneManager } from './SceneManager';\n\n/**\n * Renderer Manager\n * Handles animation loop with frame rate control\n */\nexport class RendererManager {\n private sceneManager: SceneManager;\n private animationId: number | null = null;\n private isRunning: boolean = false;\n\n private frameInterval: number;\n private lastFrameTime: number = 0;\n\n private onSimulate: () => void;\n private onRender: () => void;\n\n // Performance monitoring\n private frameCount: number = 0;\n private fpsStartTime: number = 0;\n private currentFPS: number = 60;\n\n constructor(\n sceneManager: SceneManager,\n onSimulate: () => void,\n onRender: () => void,\n targetFPS: number = 60\n ) {\n this.sceneManager = sceneManager;\n this.onSimulate = onSimulate;\n this.onRender = onRender;\n this.frameInterval = 1000 / targetFPS;\n }\n\n /**\n * Starts the animation loop\n */\n start(): void {\n if (this.isRunning) return;\n\n this.isRunning = true;\n this.lastFrameTime = performance.now();\n this.fpsStartTime = performance.now();\n this.frameCount = 0;\n\n this.animate();\n }\n\n /**\n * Stops the animation loop\n */\n stop(): void {\n this.isRunning = false;\n if (this.animationId !== null) {\n cancelAnimationFrame(this.animationId);\n this.animationId = null;\n }\n }\n\n /**\n * Main animation loop\n */\n private animate = (): void => {\n if (!this.isRunning) return;\n\n this.animationId = requestAnimationFrame(this.animate);\n\n const currentTime = performance.now();\n const elapsed = currentTime - this.lastFrameTime;\n\n // Frame rate limiting\n if (elapsed < this.frameInterval) {\n return;\n }\n\n // Update timing\n this.lastFrameTime = currentTime - (elapsed % this.frameInterval);\n\n // Update FPS counter\n this.frameCount++;\n const fpsElapsed = currentTime - this.fpsStartTime;\n if (fpsElapsed >= 1000) {\n this.currentFPS = this.frameCount / (fpsElapsed / 1000);\n this.frameCount = 0;\n this.fpsStartTime = currentTime;\n }\n\n // Run physics simulation\n this.onSimulate();\n\n // Call additional render callbacks\n this.onRender();\n\n // Render scene\n this.sceneManager.render();\n };\n\n /**\n * Gets the current FPS\n */\n getFPS(): number {\n return Math.round(this.currentFPS);\n }\n\n /**\n * Sets target FPS\n */\n setTargetFPS(fps: number): void {\n this.frameInterval = 1000 / fps;\n }\n\n /**\n * Checks if animation is running\n */\n isAnimating(): boolean {\n return this.isRunning;\n }\n\n /**\n * Dispose\n */\n dispose(): void {\n this.stop();\n }\n}\n","import * as THREE from 'three';\n\n/**\n * Material Factory\n * Creates gradient glass materials with radial transparency\n */\nexport class MaterialFactory {\n private envMap: THREE.CubeTexture | null = null;\n private materialCache: Map<string, THREE.ShaderMaterial> = new Map();\n\n // Color palette - white and tangerine\n private readonly COLORS = [\n 0xffffff, // White\n 0xff9966, // Tangerine/orange\n 0xffcc99, // Light peach\n 0xffeedd, // Cream\n 0xff8844, // Darker tangerine\n ];\n\n constructor() {\n this.createEnvironmentMap();\n }\n\n /**\n * Creates environment map for glass reflections on dark background\n */\n private createEnvironmentMap(): void {\n const size = 256;\n\n // Create gradient backgrounds for each face - dark theme\n const faces: HTMLCanvasElement[] = [];\n const faceConfigs = [\n // Subtle colored gradients for interesting reflections\n { colors: ['#1a1a2e', '#16213e', '#0f3460'] }, // +x\n { colors: ['#2d1f1f', '#1a1a1a', '#0f0f0f'] }, // -x\n { colors: ['#1f2d2d', '#1a1a2e', '#101020'] }, // +y\n { colors: ['#0a0a0a', '#050505', '#000000'] }, // -y\n { colors: ['#1a1a2e', '#0f1a2a', '#0a0a15'] }, // +z\n { colors: ['#2d1a1a', '#1a0a0a', '#0f0505'] }, // -z\n ];\n\n for (const config of faceConfigs) {\n const faceCanvas = document.createElement('canvas');\n faceCanvas.width = size;\n faceCanvas.height = size;\n const faceCtx = faceCanvas.getContext('2d')!;\n\n const gradient = faceCtx.createRadialGradient(\n size / 2, size / 2, 0,\n size / 2, size / 2, size * 0.8\n );\n gradient.addColorStop(0, config.colors[0]);\n gradient.addColorStop(0.5, config.colors[1]);\n gradient.addColorStop(1, config.colors[2]);\n\n faceCtx.fillStyle = gradient;\n faceCtx.fillRect(0, 0, size, size);\n\n // Add subtle noise\n const imageData = faceCtx.getImageData(0, 0, size, size);\n for (let i = 0; i < imageData.data.length; i += 4) {\n const noise = (Math.random() - 0.5) * 5;\n imageData.data[i] = Math.min(255, Math.max(0, imageData.data[i] + noise));\n imageData.data[i + 1] = Math.min(255, Math.max(0, imageData.data[i + 1] + noise));\n imageData.data[i + 2] = Math.min(255, Math.max(0, imageData.data[i + 2] + noise));\n }\n faceCtx.putImageData(imageData, 0, 0);\n\n faces.push(faceCanvas);\n }\n\n this.envMap = new THREE.CubeTexture(faces.map(c => {\n const img = new Image();\n img.src = c.toDataURL();\n return img;\n }));\n this.envMap.needsUpdate = true;\n }\n\n /**\n * Gets a random color from the palette\n */\n getRandomColor(): number {\n return this.COLORS[Math.floor(Math.random() * this.COLORS.length)];\n }\n\n /**\n * Creates a gradient glass material with white glow in center\n * All balls use the same tangerine color with white center glow\n */\n createGlassMaterial(_color?: number): THREE.ShaderMaterial {\n // Single consistent color - tangerine\n const color = 0xff9966;\n const cacheKey = 'glass-single';\n\n if (this.materialCache.has(cacheKey)) {\n return this.materialCache.get(cacheKey)!.clone();\n }\n\n const threeColor = new THREE.Color(color);\n\n // Custom shader for radial white glow effect\n const material = new THREE.ShaderMaterial({\n uniforms: {\n uColor: { value: threeColor },\n uEnvMap: { value: this.envMap },\n uGlowColor: { value: new THREE.Color(0xffffff) },\n uGlowIntensity: { value: 0.8 },\n uReflectivity: { value: 0.4 },\n uFresnelPower: { value: 2.5 },\n },\n vertexShader: `\n varying vec3 vNormal;\n varying vec3 vViewPosition;\n varying vec3 vWorldPosition;\n varying vec2 vUv;\n \n void main() {\n vNormal = normalize(normalMatrix * normal);\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = -mvPosition.xyz;\n vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;\n vUv = uv;\n gl_Position = projectionMatrix * mvPosition;\n }\n `,\n fragmentShader: `\n uniform vec3 uColor;\n uniform vec3 uGlowColor;\n uniform samplerCube uEnvMap;\n uniform float uGlowIntensity;\n uniform float uReflectivity;\n uniform float uFresnelPower;\n \n varying vec3 vNormal;\n varying vec3 vViewPosition;\n varying vec3 vWorldPosition;\n varying vec2 vUv;\n \n void main() {\n vec3 viewDir = normalize(vViewPosition);\n vec3 normal = normalize(vNormal);\n \n // Fresnel effect - edges are more visible\n float fresnel = pow(1.0 - abs(dot(viewDir, normal)), uFresnelPower);\n \n // Center glow: bright white in center, fading to base color at edges\n // Center is where normal faces camera directly (low fresnel)\n float centerGlow = (1.0 - fresnel) * uGlowIntensity;\n \n // Environment reflection on edges\n vec3 reflectDir = reflect(-viewDir, normal);\n vec3 envColor = textureCube(uEnvMap, reflectDir).rgb;\n \n // Base color with reflection at edges\n vec3 baseColor = uColor;\n vec3 edgeColor = mix(baseColor, envColor, uReflectivity * fresnel);\n \n // Blend: white glow in center, colored edges\n vec3 finalColor = mix(edgeColor, uGlowColor, centerGlow);\n \n // Add rim highlight for glass effect\n float rimLight = pow(fresnel, 4.0) * 0.4;\n finalColor += vec3(rimLight) * uColor;\n \n // Opacity: fully opaque with glow effect visible\n float opacity = 0.85 + fresnel * 0.15;\n \n gl_FragColor = vec4(finalColor, opacity);\n }\n `,\n transparent: true,\n side: THREE.FrontSide,\n depthWrite: true,\n blending: THREE.NormalBlending,\n });\n\n this.materialCache.set(cacheKey, material);\n return material.clone();\n }\n\n /**\n * Creates material for edges (light color for dark background)\n */\n createEdgeMaterial(color: number = 0x666666, opacity: number = 0.4): THREE.LineBasicMaterial {\n return new THREE.LineBasicMaterial({\n color: color,\n transparent: true,\n opacity: opacity,\n linewidth: 1,\n });\n }\n\n /**\n * Creates highlighted edge material\n */\n createHighlightedEdgeMaterial(): THREE.LineBasicMaterial {\n return new THREE.LineBasicMaterial({\n color: 0xff9966, // Tangerine highlight\n transparent: false,\n opacity: 1.0,\n linewidth: 2,\n });\n }\n\n /**\n * Creates a sprite material for labels (light text for dark background)\n */\n createLabelMaterial(text: string, fontSize: number = 24): THREE.SpriteMaterial {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d')!;\n\n // Set canvas size based on text length\n ctx.font = `600 ${fontSize}px Inter, -apple-system, sans-serif`;\n const metrics = ctx.measureText(text);\n const textWidth = metrics.width;\n\n canvas.width = Math.max(128, textWidth + 24);\n canvas.height = fontSize + 20;\n\n // Clear and draw text\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.font = `600 ${fontSize}px Inter, -apple-system, sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Light text with dark shadow for dark background\n ctx.shadowColor = 'rgba(0, 0, 0, 0.8)';\n ctx.shadowBlur = 4;\n ctx.shadowOffsetX = 1;\n ctx.shadowOffsetY = 1;\n\n ctx.fillStyle = 'rgba(255, 255, 255, 0.95)';\n ctx.fillText(text, canvas.width / 2, canvas.height / 2);\n\n const texture = new THREE.CanvasTexture(canvas);\n texture.needsUpdate = true;\n\n return new THREE.SpriteMaterial({\n map: texture,\n transparent: true,\n depthTest: false,\n depthWrite: false,\n });\n }\n\n /**\n * Gets environment map\n */\n getEnvMap(): THREE.CubeTexture | null {\n return this.envMap;\n }\n\n /**\n * Dispose all cached materials\n */\n dispose(): void {\n this.materialCache.forEach(material => material.dispose());\n this.materialCache.clear();\n if (this.envMap) {\n this.envMap.dispose();\n }\n }\n}\n","import * as THREE from 'three';\nimport { MaterialFactory } from './MaterialFactory';\nimport type { NodeData, LODLevel, NodeObject } from '../utils/types';\n\n/**\n * Node Factory\n * Creates glass ball nodes with labels\n */\nexport class NodeFactory {\n private materialFactory: MaterialFactory;\n private geometryCache: Map<string, THREE.SphereGeometry> = new Map();\n private nodeRadius: number;\n private lodSegments: number[];\n private defaultNodeColor: number;\n\n constructor(\n materialFactory: MaterialFactory,\n nodeRadius: number = 2,\n lodSegments: number[] = [32, 16, 8],\n defaultNodeColor: number = 0xff9966\n ) {\n this.materialFactory = materialFactory;\n this.nodeRadius = nodeRadius;\n this.lodSegments = lodSegments;\n this.defaultNodeColor = defaultNodeColor;\n this.initGeometryCache();\n }\n\n /**\n * Pre-create geometries for each LOD level\n */\n private initGeometryCache(): void {\n this.lodSegments.forEach((segments, index) => {\n const key = `lod-${index}`;\n this.geometryCache.set(\n key,\n new THREE.SphereGeometry(this.nodeRadius, segments, segments)\n );\n });\n }\n\n /**\n * Gets geometry for the specified LOD level\n */\n private getGeometry(lodLevel: LODLevel): THREE.SphereGeometry {\n const key = `lod-${lodLevel}`;\n if (this.geometryCache.has(key)) {\n return this.geometryCache.get(key)!;\n }\n // Fallback to highest detail\n return this.geometryCache.get('lod-0')!;\n }\n\n /**\n * Creates a node visual (glass ball + label)\n */\n createNode(nodeData: NodeData, lodLevel: LODLevel = 0): NodeObject {\n const group = new THREE.Group();\n group.name = `node-${nodeData.id}`;\n group.userData = { nodeId: nodeData.id, nodeData };\n\n // Create glass sphere\n const geometry = this.getGeometry(lodLevel);\n const material = this.materialFactory.createGlassMaterial(\n nodeData.color ?? this.defaultNodeColor\n );\n const sphere = new THREE.Mesh(geometry, material);\n sphere.castShadow = true;\n sphere.receiveShadow = true;\n group.add(sphere);\n\n // Create label sprite\n const labelMaterial = this.materialFactory.createLabelMaterial(nodeData.label);\n const label = new THREE.Sprite(labelMaterial);\n\n // Position label above the sphere\n label.position.y = this.nodeRadius + 1.5;\n label.scale.set(4, 1, 1);\n group.add(label);\n\n // Set initial position\n if (nodeData.position) {\n group.position.set(\n nodeData.position.x,\n nodeData.position.y,\n nodeData.position.z\n );\n }\n\n return {\n group,\n sphere,\n label,\n lodLevel,\n };\n }\n\n /**\n * Updates the LOD level of a node\n */\n updateNodeLOD(nodeObject: NodeObject, newLodLevel: LODLevel): void {\n if (nodeObject.lodLevel === newLodLevel) return;\n\n // Get new geometry\n const newGeometry = this.getGeometry(newLodLevel);\n\n // Update the sphere's geometry\n nodeObject.sphere.geometry = newGeometry;\n nodeObject.lodLevel = newLodLevel;\n }\n\n /**\n * Updates the color of a node\n */\n updateNodeColor(nodeObject: NodeObject, color: number): void {\n // Dispose old material and create new one\n if (nodeObject.sphere.material instanceof THREE.Material) {\n nodeObject.sphere.material.dispose();\n }\n nodeObject.sphere.material = this.materialFactory.createGlassMaterial(color);\n }\n\n /**\n * Updates the label of a node\n */\n updateNodeLabel(nodeObject: NodeObject, label: string): void {\n // Dispose old sprite material\n if (nodeObject.label.material instanceof THREE.SpriteMaterial) {\n if (nodeObject.label.material.map) {\n nodeObject.label.material.map.dispose();\n }\n nodeObject.label.material.dispose();\n }\n\n // Create new label material\n nodeObject.label.material = this.materialFactory.createLabelMaterial(label);\n }\n\n /**\n * Disposes a node's resources\n */\n disposeNode(nodeObject: NodeObject): void {\n // Dispose sphere material\n if (nodeObject.sphere.material instanceof THREE.Material) {\n nodeObject.sphere.material.dispose();\n }\n\n // Dispose label\n if (nodeObject.label.material instanceof THREE.SpriteMaterial) {\n if (nodeObject.label.material.map) {\n nodeObject.label.material.map.dispose();\n }\n nodeObject.label.material.dispose();\n }\n }\n\n /**\n * Dispose factory resources\n */\n dispose(): void {\n this.geometryCache.forEach(geometry => geometry.dispose());\n this.geometryCache.clear();\n }\n}\n","import * as THREE from 'three';\nimport { MaterialFactory } from './MaterialFactory';\nimport type { EdgeObject, Vector3Data, Edge, NodeData } from '../utils/types';\n\n/**\n * Edge Factory\n * Creates edge lines between nodes with hover highlighting support\n */\nexport class EdgeFactory {\n private materialFactory: MaterialFactory;\n private edgeColor: number;\n private edgeOpacity: number;\n private defaultMaterial: THREE.LineBasicMaterial | null = null;\n private highlightMaterial: THREE.LineBasicMaterial | null = null;\n\n constructor(\n materialFactory: MaterialFactory,\n edgeColor: number = 0x999999,\n edgeOpacity: number = 0.5\n ) {\n this.materialFactory = materialFactory;\n this.edgeColor = edgeColor;\n this.edgeOpacity = edgeOpacity;\n }\n\n /**\n * Gets or creates the default edge material\n */\n private getDefaultMaterial(): THREE.LineBasicMaterial {\n if (!this.defaultMaterial) {\n this.defaultMaterial = this.materialFactory.createEdgeMaterial(\n this.edgeColor,\n this.edgeOpacity\n );\n }\n return this.defaultMaterial;\n }\n\n /**\n * Gets or creates the highlight material\n */\n private getHighlightMaterial(): THREE.LineBasicMaterial {\n if (!this.highlightMaterial) {\n this.highlightMaterial = this.materialFactory.createHighlightedEdgeMaterial();\n }\n return this.highlightMaterial;\n }\n\n /**\n * Creates an edge line between two positions\n */\n createEdge(\n edge: Edge,\n sourceNode: NodeData,\n targetNode: NodeData,\n sourcePos: Vector3Data,\n targetPos: Vector3Data\n ): EdgeObject {\n const geometry = new THREE.BufferGeometry();\n\n // Set initial positions\n const positions = new Float32Array([\n sourcePos.x, sourcePos.y, sourcePos.z,\n targetPos.x, targetPos.y, targetPos.z,\n ]);\n geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));\n\n const material = this.getDefaultMaterial().clone();\n\n const line = new THREE.Line(geometry, material);\n line.name = `edge-${edge.source}-${edge.target}`;\n\n // Store full edge and node data for hover detection\n line.userData = {\n source: edge.source,\n target: edge.target,\n edge: edge,\n sourceNode: sourceNode,\n targetNode: targetNode,\n };\n line.frustumCulled = true;\n\n return {\n line,\n source: edge.source,\n target: edge.target,\n };\n }\n\n /**\n * Highlights an edge\n */\n highlightEdge(edgeObject: EdgeObject): void {\n if (edgeObject.line.material instanceof THREE.Material) {\n edgeObject.line.material.dispose();\n }\n edgeObject.line.material = this.getHighlightMaterial().clone();\n }\n\n /**\n * Resets an edge to default appearance\n */\n unhighlightEdge(edgeObject: EdgeObject): void {\n if (edgeObject.line.material instanceof THREE.Material) {\n edgeObject.line.material.dispose();\n }\n edgeObject.line.material = this.getDefaultMaterial().clone();\n }\n\n /**\n * Updates an edge's positions\n */\n updateEdgePositions(\n edgeObject: EdgeObject,\n sourcePos: Vector3Data,\n targetPos: Vector3Data\n ): void {\n const positions = edgeObject.line.geometry.attributes.position;\n const posArray = positions.array as Float32Array;\n\n posArray[0] = sourcePos.x;\n posArray[1] = sourcePos.y;\n posArray[2] = sourcePos.z;\n posArray[3] = targetPos.x;\n posArray[4] = targetPos.y;\n posArray[5] = targetPos.z;\n\n positions.needsUpdate = true;\n edgeObject.line.geometry.computeBoundingSphere();\n }\n\n /**\n * Disposes an edge's resources\n */\n disposeEdge(edgeObject: EdgeObject): void {\n edgeObject.line.geometry.dispose();\n if (edgeObject.line.material instanceof THREE.Material) {\n edgeObject.line.material.dispose();\n }\n }\n\n /**\n * Dispose factory resources\n */\n dispose(): void {\n if (this.defaultMaterial) {\n this.defaultMaterial.dispose();\n }\n if (this.highlightMaterial) {\n this.highlightMaterial.dispose();\n }\n }\n}\n","import * as THREE from 'three';\nimport type { LODLevel, Vector3Data } from '../utils/types';\nimport { LODLevel as LODLevelEnum } from '../utils/types';\n\n/**\n * LOD Manager\n * Manages Level of Detail for nodes based on distance from camera\n */\nexport class LODManager {\n private camera: THREE.PerspectiveCamera;\n private lodDistances: number[];\n private enabled: boolean;\n\n constructor(\n camera: THREE.PerspectiveCamera,\n lodDistances: number[] = [50, 100, 200],\n enabled: boolean = true\n ) {\n this.camera = camera;\n this.lodDistances = lodDistances;\n this.enabled = enabled;\n }\n\n /**\n * Gets the LOD level for a position based on distance from camera\n */\n getLODLevel(position: Vector3Data): LODLevel {\n if (!this.enabled) {\n return LODLevelEnum.HIGH;\n }\n\n const dx = position.x - this.camera.position.x;\n const dy = position.y - this.camera.position.y;\n const dz = position.z - this.camera.position.z;\n const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n if (distance < this.lodDistances[0]) {\n return LODLevelEnum.HIGH;\n } else if (distance < this.lodDistances[1]) {\n return LODLevelEnum.MEDIUM;\n } else {\n return LODLevelEnum.LOW;\n }\n }\n\n /**\n * Checks if a node should be visible based on distance\n */\n shouldRenderNode(position: Vector3Data, maxDistance: number = 500): boolean {\n const dx = position.x - this.camera.position.x;\n const dy = position.y - this.camera.position.y;\n const dz = position.z - this.camera.position.z;\n const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n return distance < maxDistance;\n }\n\n /**\n * Sets the LOD distances\n */\n setLODDistances(distances: number[]): void {\n this.lodDistances = distances;\n }\n\n /**\n * Enables/disables LOD\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n}\n","import * as THREE from 'three';\nimport type { Vector3Data } from '../utils/types';\n\n/**\n * Frustum Culler\n * Determines which objects are visible in the camera's viewport\n */\nexport class FrustumCuller {\n private camera: THREE.PerspectiveCamera;\n private frustum: THREE.Frustum;\n private projScreenMatrix: THREE.Matrix4;\n private enabled: boolean;\n\n constructor(camera: THREE.PerspectiveCamera, enabled: boolean = true) {\n this.camera = camera;\n this.frustum = new THREE.Frustum();\n this.projScreenMatrix = new THREE.Matrix4();\n this.enabled = enabled;\n }\n\n /**\n * Updates the frustum from the camera\n */\n update(): void {\n this.projScreenMatrix.multiplyMatrices(\n this.camera.projectionMatrix,\n this.camera.matrixWorldInverse\n );\n this.frustum.setFromProjectionMatrix(this.projScreenMatrix);\n }\n\n /**\n * Checks if a point is inside the frustum\n */\n isPointVisible(position: Vector3Data): boolean {\n if (!this.enabled) return true;\n\n const point = new THREE.Vector3(position.x, position.y, position.z);\n return this.frustum.containsPoint(point);\n }\n\n /**\n * Checks if a sphere is inside or intersects the frustum\n */\n isSphereVisible(position: Vector3Data, radius: number): boolean {\n if (!this.enabled) return true;\n\n const sphere = new THREE.Sphere(\n new THREE.Vector3(position.x, position.y, position.z),\n radius\n );\n return this.frustum.intersectsSphere(sphere);\n }\n\n /**\n * Checks if a line segment is potentially visible\n */\n isLineVisible(start: Vector3Data, end: Vector3Data): boolean {\n if (!this.enabled) return true;\n\n // Quick check: if either endpoint is visible, the line might be visible\n const startPoint = new THREE.Vector3(start.x, start.y, start.z);\n const endPoint = new THREE.Vector3(end.x, end.y, end.z);\n\n if (this.frustum.containsPoint(startPoint) || this.frustum.containsPoint(endPoint)) {\n return true;\n }\n\n // Create a bounding sphere around the line\n const center = new THREE.Vector3(\n (start.x + end.x) / 2,\n (start.y + end.y) / 2,\n (start.z + end.z) / 2\n );\n const radius = center.distanceTo(startPoint);\n const sphere = new THREE.Sphere(center, radius);\n\n return this.frustum.intersectsSphere(sphere);\n }\n\n /**\n * Enables/disables frustum culling\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n}\n","import * as THREE from 'three';\nimport { SceneManager } from '../core/SceneManager';\nimport type { NodeData, Edge } from '../utils/types';\n\n/**\n * Edge hover info returned by raycaster\n */\nexport interface EdgeHoverInfo {\n edge: Edge;\n sourceNode: NodeData;\n targetNode: NodeData;\n edgeLine: THREE.Line;\n}\n\n/**\n * Raycaster Manager\n * Handles click and hover detection on nodes and edges\n */\nexport class RaycasterManager {\n private sceneManager: SceneManager;\n private raycaster: THREE.Raycaster;\n private mouse: THREE.Vector2;\n private container: HTMLElement;\n\n private onNodeClick: ((nodeData: NodeData) => void) | null = null;\n private onNodeHover: ((nodeData: NodeData | null) => void) | null = null;\n private onEdgeHover: ((info: EdgeHoverInfo | null) => void) | null = null;\n private onEdgeClick: ((info: EdgeHoverInfo) => void) | null = null;\n\n private hoveredNodeId: string | null = null;\n private hoveredEdgeKey: string | null = null;\n\n private nodeObjects: THREE.Object3D[] = [];\n private edgeObjects: THREE.Line[] = [];\n\n constructor(sceneManager: SceneManager, container: HTMLElement) {\n this.sceneManager = sceneManager;\n this.container = container;\n this.raycaster = new THREE.Raycaster();\n this.raycaster.params.Line = { threshold: 1.5 }; // Increased threshold for easier relationship clicking\n this.mouse = new THREE.Vector2();\n\n // Bind event handlers\n this.handleClick = this.handleClick.bind(this);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n\n // Add event listeners\n container.addEventListener('click', this.handleClick);\n container.addEventListener('mousemove', this.handleMouseMove);\n }\n\n /**\n * Updates the list of node objects to raycast against\n */\n setNodeObjects(objects: THREE.Object3D[]): void {\n this.nodeObjects = objects;\n }\n\n /**\n * Updates the list of edge objects to raycast against\n */\n setEdgeObjects(objects: THREE.Line[]): void {\n this.edgeObjects = objects;\n }\n\n /**\n * Sets the click callback\n */\n setClickCallback(callback: ((nodeData: NodeData) => void) | null): void {\n this.onNodeClick = callback;\n }\n\n /**\n * Sets the node hover callback\n */\n setHoverCallback(callback: ((nodeData: NodeData | null) => void) | null): void {\n this.onNodeHover = callback;\n }\n\n /**\n * Sets the edge hover callback\n */\n setEdgeHoverCallback(callback: ((info: EdgeHoverInfo | null) => void) | null): void {\n this.onEdgeHover = callback;\n }\n\n /**\n * Sets the edge click callback\n */\n setEdgeClickCallback(callback: ((info: EdgeHoverInfo) => void) | null): void {\n this.onEdgeClick = callback;\n }\n\n /**\n * Handles click events\n */\n private handleClick(event: MouseEvent): void {\n // Check for node click first (priority over edges)\n const nodeData = this.getIntersectedNode(event);\n\n if (nodeData && this.onNodeClick) {\n this.onNodeClick(nodeData);\n return;\n }\n\n // Check for edge click if no node was clicked\n const edgeInfo = this.getIntersectedEdge(event);\n if (edgeInfo && this.onEdgeClick) {\n this.onEdgeClick(edgeInfo);\n }\n }\n\n /**\n * Handles mouse move events for hover detection\n */\n private handleMouseMove(event: MouseEvent): void {\n // Check node hover first (priority over edges)\n const nodeData = this.getIntersectedNode(event);\n const newHoveredNodeId = nodeData?.id ?? null;\n\n if (newHoveredNodeId !== this.hoveredNodeId) {\n this.hoveredNodeId = newHoveredNodeId;\n\n if (this.onNodeHover) {\n this.onNodeHover(nodeData);\n }\n }\n\n // If hovering a node, clear edge hover\n if (nodeData) {\n if (this.hoveredEdgeKey !== null && this.onEdgeHover) {\n this.hoveredEdgeKey = null;\n this.onEdgeHover(null);\n }\n this.container.style.cursor = 'pointer';\n return;\n }\n\n // Check edge hover\n const edgeInfo = this.getIntersectedEdge(event);\n const newHoveredEdgeKey = edgeInfo ? `${edgeInfo.edge.source}-${edgeInfo.edge.target}` : null;\n\n if (newHoveredEdgeKey !== this.hoveredEdgeKey) {\n this.hoveredEdgeKey = newHoveredEdgeKey;\n\n if (this.onEdgeHover) {\n this.onEdgeHover(edgeInfo);\n }\n }\n\n // Update cursor\n this.container.style.cursor = edgeInfo ? 'pointer' : 'default';\n }\n\n /**\n * Gets the intersected node from a mouse event\n */\n private getIntersectedNode(event: MouseEvent): NodeData | null {\n const rect = this.container.getBoundingClientRect();\n\n this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;\n\n this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);\n\n // Check all node groups\n const intersects = this.raycaster.intersectObjects(this.nodeObjects, true);\n\n if (intersects.length > 0) {\n // Find the parent group that contains the nodeData\n let obj: THREE.Object3D | null = intersects[0].object;\n\n while (obj) {\n if (obj.userData?.nodeData) {\n return obj.userData.nodeData as NodeData;\n }\n obj = obj.parent;\n }\n }\n\n return null;\n }\n\n /**\n * Gets the intersected edge from a mouse event\n */\n private getIntersectedEdge(event: MouseEvent): EdgeHoverInfo | null {\n const rect = this.container.getBoundingClientRect();\n\n this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;\n\n this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);\n\n // Check edge lines\n const intersects = this.raycaster.intersectObjects(this.edgeObjects, false);\n\n if (intersects.length > 0) {\n const line = intersects[0].object as THREE.Line;\n const userData = line.userData;\n\n if (userData?.edge && userData?.sourceNode && userData?.targetNode) {\n return {\n edge: userData.edge as Edge,\n sourceNode: userData.sourceNode as NodeData,\n targetNode: userData.targetNode as NodeData,\n edgeLine: line,\n };\n }\n }\n\n return null;\n }\n\n /**\n * Performs a raycast and returns the intersected node ID\n */\n getIntersectedNodeId(screenX: number, screenY: number): string | null {\n const rect = this.container.getBoundingClientRect();\n\n this.mouse.x = ((screenX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((screenY - rect.top) / rect.height) * 2 + 1;\n\n this.raycaster.setFromCamera(this.mouse, this.sceneManager.camera);\n\n const intersects = this.raycaster.intersectObjects(this.nodeObjects, true);\n\n if (intersects.length > 0) {\n let obj: THREE.Object3D | null = intersects[0].object;\n\n while (obj) {\n if (obj.userData?.nodeId) {\n return obj.userData.nodeId as string;\n }\n obj = obj.parent;\n }\n }\n\n return null;\n }\n\n /**\n * Dispose resources and remove event listeners\n */\n dispose(): void {\n this.container.removeEventListener('click', this.handleClick);\n this.container.removeEventListener('mousemove', this.handleMouseMove);\n }\n}\n","import type { NodeData } from '../utils/types';\n\n/**\n * Panel Manager\n * Handles the glassmorphic info panel for nodes\n */\nexport class PanelManager {\n private container: HTMLElement;\n private panel: HTMLElement | null = null;\n private currentNodeId: string | null = null;\n private visible: boolean = false;\n\n private panelTemplate: ((nodeData: NodeData, neighbors: NodeData[]) => string) | null = null;\n private panelStyles: Record<string, string> = {};\n private onExpand: ((nodeId: string, depth: number) => void) | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n this.createPanel();\n }\n\n /**\n * Creates the panel element\n */\n private createPanel(): void {\n this.panel = document.createElement('div');\n this.panel.className = 'force-graph-panel';\n this.panel.style.cssText = `\n position: absolute;\n right: 20px;\n top: 50%;\n transform: translateY(-50%);\n width: 280px;\n max-height: 80vh;\n overflow-y: auto;\n background: rgba(15, 15, 25, 0.85);\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n padding: 24px;\n color: white;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n box-shadow: \n 0 8px 32px rgba(0, 0, 0, 0.4),\n inset 0 0 0 1px rgba(255, 255, 255, 0.05);\n z-index: 1000;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease, transform 0.3s ease;\n `;\n\n // Apply custom styles\n Object.entries(this.panelStyles).forEach(([key, value]) => {\n this.panel!.style.setProperty(key, value);\n });\n\n this.container.appendChild(this.panel);\n }\n\n /**\n * Sets the panel template function\n */\n setPanelTemplate(template: ((nodeData: NodeData, neighbors: NodeData[]) => string) | null): void {\n this.panelTemplate = template;\n }\n\n /**\n * Sets custom panel styles\n */\n setPanelStyles(styles: Record<string, string>): void {\n this.panelStyles = styles;\n if (this.panel) {\n Object.entries(styles).forEach(([key, value]) => {\n this.panel!.style.setProperty(key, value);\n });\n }\n }\n\n /**\n * Sets the expand callback\n */\n setExpandCallback(callback: ((nodeId: string, depth: number) => void) | null): void {\n this.onExpand = callback;\n }\n\n /**\n * Shows the panel with node information\n */\n show(nodeData: NodeData, neighbors: NodeData[]): void {\n if (!this.panel) return;\n\n this.currentNodeId = nodeData.id;\n\n // Generate content\n let content: string;\n\n if (this.panelTemplate) {\n content = this.panelTemplate(nodeData, neighbors);\n } else {\n content = this.generateDefaultContent(nodeData, neighbors);\n }\n\n this.panel.innerHTML = content;\n\n // Attach event listeners to buttons\n const expandBtn = this.panel.querySelector('[data-action=\"expand\"]');\n const depthSelect = this.panel.querySelector('[data-depth-select]') as HTMLSelectElement;\n if (expandBtn && this.onExpand) {\n expandBtn.addEventListener('click', () => {\n if (this.currentNodeId) {\n const depth = depthSelect ? parseInt(depthSelect.value, 10) : 1;\n this.onExpand!(this.currentNodeId, depth);\n }\n });\n }\n\n const closeBtn = this.panel.querySelector('[data-action=\"close\"]');\n if (closeBtn) {\n closeBtn.addEventListener('click', () => {\n this.hide();\n });\n }\n\n // Show panel with animation\n this.panel.style.opacity = '1';\n this.panel.style.pointerEvents = 'auto';\n this.panel.style.transform = 'translateY(-50%) translateX(0)';\n this.visible = true;\n }\n\n /**\n * Generates default panel content\n */\n private generateDefaultContent(nodeData: NodeData, neighbors: NodeData[]): string {\n const colorHex = nodeData.color\n ? `#${nodeData.color.toString(16).padStart(6, '0')}`\n : '#4A90E2';\n\n return `\n <style>\n .force-graph-panel h2 {\n margin: 0 0 16px 0;\n font-size: 20px;\n font-weight: 600;\n letter-spacing: -0.5px;\n display: flex;\n align-items: center;\n gap: 10px;\n overflow: hidden;\n }\n .force-graph-panel .node-label-text {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n }\n .force-graph-panel .color-dot {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background: ${colorHex};\n box-shadow: 0 0 10px ${colorHex}80;\n }\n .force-graph-panel .info-row {\n display: flex;\n justify-content: space-between;\n padding: 8px 0;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n font-size: 13px;\n }\n .force-graph-panel .info-row:last-child {\n border-bottom: none;\n }\n .force-graph-panel .info-label {\n color: rgba(255, 255, 255, 0.6);\n }\n .force-graph-panel .info-value {\n color: rgba(255, 255, 255, 0.95);\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 180px;\n text-align: right;\n }\n .force-graph-panel .neighbors-section {\n margin-top: 16px;\n }\n .force-graph-panel .neighbors-title {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 1px;\n color: rgba(255, 255, 255, 0.5);\n margin-bottom: 8px;\n }\n .force-graph-panel .neighbor-chip {\n display: inline-block;\n padding: 4px 10px;\n margin: 2px;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n font-size: 12px;\n }\n .force-graph-panel .depth-selector {\n margin-top: 16px;\n margin-bottom: 8px;\n }\n .force-graph-panel .depth-label {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.6);\n margin-bottom: 6px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n .force-graph-panel select {\n width: 100%;\n padding: 8px 12px;\n background: rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 6px;\n color: white;\n font-size: 13px;\n cursor: pointer;\n outline: none;\n transition: all 0.2s ease;\n }\n .force-graph-panel select:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n .force-graph-panel select:focus {\n border-color: rgba(96, 165, 250, 0.5);\n }\n .force-graph-panel .btn-row {\n display: flex;\n gap: 8px;\n margin-top: 20px;\n }\n .force-graph-panel button {\n flex: 1;\n padding: 10px 16px;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n .force-graph-panel .btn-expand {\n background: linear-gradient(135deg, #60a5fa, #a78bfa);\n color: white;\n }\n .force-graph-panel .btn-expand:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(96, 165, 250, 0.4);\n }\n .force-graph-panel .btn-close {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.8);\n }\n .force-graph-panel .btn-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n </style>\n \n <h2>\n <span class=\"color-dot\"></span>\n <span class=\"node-label-text\">${this.escapeHtml(nodeData.label)}</span>\n </h2>\n \n <div class=\"info-row\">\n <span class=\"info-label\">ID</span>\n <span class=\"info-value\" title=\"${this.escapeHtml(nodeData.id)}\">${this.escapeHtml(nodeData.id)}</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">Connections</span>\n <span class=\"info-value\">${neighbors.length}</span>\n </div>\n \n ${neighbors.length > 0 ? `\n <div class=\"neighbors-section\">\n <div class=\"neighbors-title\">Connected To</div>\n ${neighbors.slice(0, 5).map(n =>\n `<span class=\"neighbor-chip\">${this.escapeHtml(n.label)}</span>`\n ).join('')}\n ${neighbors.length > 5 ? `<span class=\"neighbor-chip\">+${neighbors.length - 5} more</span>` : ''}\n </div>\n ` : ''}\n \n <div class=\"depth-selector\">\n <div class=\"depth-label\">Expansion Depth</div>\n <select data-depth-select>\n <option value=\"1\">1 Level</option>\n <option value=\"2\">2 Levels</option>\n <option value=\"3\" selected>3 Levels</option>\n </select>\n </div>\n\n \n <div class=\"btn-row\">\n <button class=\"btn-expand\" data-action=\"expand\">Expand</button>\n <button class=\"btn-close\" data-action=\"close\">Close</button>\n </div>\n `;\n }\n\n /**\n * Escapes HTML to prevent XSS\n */\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /**\n * Hides the panel\n */\n hide(): void {\n if (!this.panel) return;\n\n this.panel.style.opacity = '0';\n this.panel.style.pointerEvents = 'none';\n this.panel.style.transform = 'translateY(-50%) translateX(20px)';\n this.visible = false;\n this.currentNodeId = null;\n }\n\n /**\n * Checks if the panel is visible\n */\n isVisible(): boolean {\n return this.visible;\n }\n\n /**\n * Gets the currently displayed node ID\n */\n getCurrentNodeId(): string | null {\n return this.currentNodeId;\n }\n\n /**\n * Dispose the panel\n */\n dispose(): void {\n if (this.panel && this.panel.parentNode) {\n this.panel.parentNode.removeChild(this.panel);\n }\n this.panel = null;\n }\n}\n","import type { Edge, NodeData } from '../utils/types';\n\n/**\n * Edge Panel Manager\n * Handles the glassmorphic info panel for edges/relationships\n */\nexport class EdgePanelManager {\n private container: HTMLElement;\n private panel: HTMLElement | null = null;\n private currentEdgeKey: string | null = null;\n private visible: boolean = false;\n\n private panelTemplate: ((edge: Edge, sourceNode: NodeData, targetNode: NodeData) => string) | null = null;\n private onClose: (() => void) | null = null;\n private onNodeClick: ((nodeId: string) => void) | null = null;\n\n constructor(container: HTMLElement) {\n this.container = container;\n this.createPanel();\n }\n\n /**\n * Creates the panel element\n */\n private createPanel(): void {\n this.panel = document.createElement('div');\n this.panel.className = 'force-graph-edge-panel';\n this.panel.style.cssText = `\n position: absolute;\n right: 20px;\n top: 50%;\n transform: translateY(-50%);\n width: 300px;\n max-height: 80vh;\n overflow-y: auto;\n background: rgba(15, 15, 25, 0.85);\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n padding: 24px;\n color: white;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n box-shadow: \n 0 8px 32px rgba(0, 0, 0, 0.4),\n inset 0 0 0 1px rgba(255, 255, 255, 0.05);\n z-index: 1000;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease, transform 0.3s ease;\n `;\n\n this.container.appendChild(this.panel);\n }\n\n /**\n * Sets the panel template function\n */\n setPanelTemplate(template: ((edge: Edge, sourceNode: NodeData, targetNode: NodeData) => string) | null): void {\n this.panelTemplate = template;\n }\n\n /**\n * Sets the close callback\n */\n setCloseCallback(callback: (() => void) | null): void {\n this.onClose = callback;\n }\n\n /**\n * Sets the node click callback (for navigating to nodes from edge panel)\n */\n setNodeClickCallback(callback: ((nodeId: string) => void) | null): void {\n this.onNodeClick = callback;\n }\n\n /**\n * Shows the panel with edge/relationship information\n */\n show(edge: Edge, sourceNode: NodeData, targetNode: NodeData): void {\n if (!this.panel) return;\n\n this.currentEdgeKey = `${edge.source}-${edge.target}`;\n\n // Generate content\n let content: string;\n\n if (this.panelTemplate) {\n content = this.panelTemplate(edge, sourceNode, targetNode);\n } else {\n content = this.generateDefaultContent(edge, sourceNode, targetNode);\n }\n\n this.panel.innerHTML = content;\n\n // Attach event listeners\n const closeBtn = this.panel.querySelector('[data-action=\"close\"]');\n if (closeBtn) {\n closeBtn.addEventListener('click', () => {\n this.hide();\n if (this.onClose) {\n this.onClose();\n }\n });\n }\n\n // Node click handlers\n const sourceBtn = this.panel.querySelector('[data-action=\"goto-source\"]');\n if (sourceBtn && this.onNodeClick) {\n sourceBtn.addEventListener('click', () => {\n if (this.onNodeClick) {\n this.onNodeClick(edge.source);\n }\n });\n }\n\n const targetBtn = this.panel.querySelector('[data-action=\"goto-target\"]');\n if (targetBtn && this.onNodeClick) {\n targetBtn.addEventListener('click', () => {\n if (this.onNodeClick) {\n this.onNodeClick(edge.target);\n }\n });\n }\n\n // Show panel with animation\n this.panel.style.opacity = '1';\n this.panel.style.pointerEvents = 'auto';\n this.panel.style.transform = 'translateY(-50%) translateX(0)';\n this.visible = true;\n }\n\n /**\n * Generates default panel content\n */\n private generateDefaultContent(edge: Edge, sourceNode: NodeData, targetNode: NodeData): string {\n const sourceColorHex = sourceNode.color\n ? `#${sourceNode.color.toString(16).padStart(6, '0')}`\n : '#ff9966';\n const targetColorHex = targetNode.color\n ? `#${targetNode.color.toString(16).padStart(6, '0')}`\n : '#ff9966';\n\n const relationship = edge.relationship || 'connected to';\n\n return `\n <style>\n .force-graph-edge-panel .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 20px;\n }\n .force-graph-edge-panel .panel-title {\n font-size: 14px;\n text-transform: uppercase;\n letter-spacing: 1px;\n color: rgba(255, 255, 255, 0.6);\n margin: 0;\n }\n .force-graph-edge-panel .relationship-section {\n background: rgba(255, 255, 255, 0.05);\n border-radius: 12px;\n padding: 16px;\n text-align: center;\n margin-bottom: 20px;\n }\n .force-graph-edge-panel .relationship-label {\n font-size: 18px;\n font-weight: 600;\n color: #a78bfa;\n letter-spacing: 0.5px;\n }\n .force-graph-edge-panel .node-card {\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n padding: 14px;\n margin-bottom: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n .force-graph-edge-panel .node-card:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n transform: translateX(4px);\n }\n .force-graph-edge-panel .node-card-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 6px;\n }\n .force-graph-edge-panel .node-type {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 1px;\n color: rgba(255, 255, 255, 0.5);\n }\n .force-graph-edge-panel .color-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n .force-graph-edge-panel .node-label {\n font-size: 15px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.95);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .force-graph-edge-panel .connection-arrow {\n text-align: center;\n color: rgba(255, 255, 255, 0.4);\n font-size: 18px;\n margin: 8px 0;\n }\n .force-graph-edge-panel .btn-close {\n width: 100%;\n padding: 12px 16px;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.8);\n margin-top: 16px;\n }\n .force-graph-edge-panel .btn-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n .force-graph-edge-panel .hint-text {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n text-align: center;\n margin-top: 8px;\n }\n </style>\n \n <div class=\"panel-header\">\n <h3 class=\"panel-title\">Relationship</h3>\n </div>\n \n <div class=\"relationship-section\">\n <span class=\"relationship-label\">${this.escapeHtml(relationship)}</span>\n </div>\n \n <div class=\"node-card\" data-action=\"goto-source\" title=\"Click to focus on ${this.escapeHtml(sourceNode.label)}\">\n <div class=\"node-type\">Source</div>\n <div class=\"node-card-header\">\n <span class=\"color-dot\" style=\"background: ${sourceColorHex}; box-shadow: 0 0 8px ${sourceColorHex}80;\"></span>\n <span class=\"node-label\">${this.escapeHtml(sourceNode.label)}</span>\n </div>\n </div>\n \n <div class=\"connection-arrow\">↓</div>\n \n <div class=\"node-card\" data-action=\"goto-target\" title=\"Click to focus on ${this.escapeHtml(targetNode.label)}\">\n <div class=\"node-type\">Target</div>\n <div class=\"node-card-header\">\n <span class=\"color-dot\" style=\"background: ${targetColorHex}; box-shadow: 0 0 8px ${targetColorHex}80;\"></span>\n <span class=\"node-label\">${this.escapeHtml(targetNode.label)}</span>\n </div>\n </div>\n \n <p class=\"hint-text\">Click on a node to focus on it</p>\n \n <button class=\"btn-close\" data-action=\"close\">Close</button>\n `;\n }\n\n /**\n * Escapes HTML to prevent XSS\n */\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /**\n * Hides the panel\n */\n hide(): void {\n if (!this.panel) return;\n\n this.panel.style.opacity = '0';\n this.panel.style.pointerEvents = 'none';\n this.panel.style.transform = 'translateY(-50%) translateX(20px)';\n this.visible = false;\n this.currentEdgeKey = null;\n }\n\n /**\n * Checks if the panel is visible\n */\n isVisible(): boolean {\n return this.visible;\n }\n\n /**\n * Gets the currently displayed edge key\n */\n getCurrentEdgeKey(): string | null {\n return this.currentEdgeKey;\n }\n\n /**\n * Dispose the panel\n */\n dispose(): void {\n if (this.panel && this.panel.parentNode) {\n this.panel.parentNode.removeChild(this.panel);\n }\n this.panel = null;\n }\n}\n","import type { Edge, NodeData } from '../utils/types';\n\n/**\n * Edge Tooltip Manager\n * Shows relationship info when hovering over edges\n */\nexport class EdgeTooltipManager {\n private tooltip: HTMLElement | null = null;\n private visible: boolean = false;\n\n constructor() {\n this.createTooltip();\n this.setupMouseTracking();\n }\n\n /**\n * Creates the tooltip element\n */\n private createTooltip(): void {\n this.tooltip = document.createElement('div');\n this.tooltip.className = 'force-graph-edge-tooltip';\n this.tooltip.style.cssText = `\n position: fixed;\n padding: 10px 14px;\n background: rgba(30, 30, 30, 0.95);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 8px;\n color: white;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 13px;\n pointer-events: none;\n z-index: 10000;\n opacity: 0;\n transform: translateY(5px);\n transition: opacity 0.15s ease, transform 0.15s ease;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n max-width: 400px;\n white-space: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n `;\n\n document.body.appendChild(this.tooltip);\n }\n\n /**\n * Sets up mouse tracking for tooltip following\n */\n private setupMouseTracking(): void {\n document.addEventListener('mousemove', (e) => {\n if (this.visible && this.tooltip) {\n this.positionTooltip(e.clientX, e.clientY);\n }\n });\n }\n\n /**\n * Positions the tooltip near the mouse\n */\n private positionTooltip(mouseX: number, mouseY: number): void {\n if (!this.tooltip) return;\n\n const tooltipRect = this.tooltip.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let left = mouseX + 15;\n let top = mouseY + 15;\n\n // Keep tooltip within viewport bounds\n if (left + tooltipRect.width > viewportWidth - 10) {\n left = mouseX - tooltipRect.width - 15;\n }\n if (top + tooltipRect.height > viewportHeight - 10) {\n top = mouseY - tooltipRect.height - 15;\n }\n if (left < 10) {\n left = 10;\n }\n if (top < 10) {\n top = 10;\n }\n\n this.tooltip.style.left = `${left}px`;\n this.tooltip.style.top = `${top}px`;\n }\n\n /**\n * Shows the tooltip with edge info\n */\n show(\n edge: Edge,\n sourceNode: NodeData,\n targetNode: NodeData,\n mouseX: number,\n mouseY: number\n ): void {\n if (!this.tooltip) return;\n\n const relationship = edge.relationship || 'connected to';\n\n // Generate content with proper text wrapping\n this.tooltip.innerHTML = `\n <div style=\"display: flex; flex-direction: column; gap: 4px;\">\n <div style=\"display: flex; align-items: center; gap: 6px; flex-wrap: wrap;\">\n <span style=\"font-weight: 600; color: #ff9966;\">${this.escapeHtml(sourceNode.label)}</span>\n </div>\n <div style=\"color: rgba(255, 255, 255, 0.6); font-style: italic; font-size: 12px; padding-left: 8px;\">\n ↳ ${this.escapeHtml(relationship)}\n </div>\n <div style=\"display: flex; align-items: center; gap: 6px; flex-wrap: wrap;\">\n <span style=\"font-weight: 600; color: #ff9966;\">${this.escapeHtml(targetNode.label)}</span>\n </div>\n </div>\n `;\n\n // Position and show\n this.positionTooltip(mouseX, mouseY);\n this.tooltip.style.opacity = '1';\n this.tooltip.style.transform = 'translateY(0)';\n this.visible = true;\n }\n\n /**\n * Updates tooltip position (called externally on mouse move)\n */\n updatePosition(mouseX: number, mouseY: number): void {\n if (this.visible) {\n this.positionTooltip(mouseX, mouseY);\n }\n }\n\n /**\n * Hides the tooltip\n */\n hide(): void {\n if (!this.tooltip) return;\n\n this.tooltip.style.opacity = '0';\n this.tooltip.style.transform = 'translateY(5px)';\n this.visible = false;\n }\n\n /**\n * Checks if tooltip is visible\n */\n isVisible(): boolean {\n return this.visible;\n }\n\n /**\n * Escapes HTML to prevent XSS\n */\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /**\n * Dispose the tooltip\n */\n dispose(): void {\n if (this.tooltip && this.tooltip.parentNode) {\n this.tooltip.parentNode.removeChild(this.tooltip);\n }\n this.tooltip = null;\n }\n}\n","import type { NodeData, Edge } from '../utils/types';\n\n/**\n * Search Manager\n * Handles the glassmorphic search UI and results dropdown\n */\nexport class SearchManager {\n private container: HTMLElement;\n private searchContainer: HTMLElement | null = null;\n private searchInput: HTMLInputElement | null = null;\n private searchResults: HTMLElement | null = null;\n private searchTimeout: number | null = null;\n private placeholder: string;\n\n private onSearch: (query: string) => { nodeResults: NodeData[], edgeResults: Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> };\n private onResultClick: (nodeId: string) => void;\n\n constructor(\n container: HTMLElement,\n options: {\n placeholder?: string,\n onSearch: (query: string) => { nodeResults: NodeData[], edgeResults: Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> },\n onResultClick: (nodeId: string) => void\n }\n ) {\n this.container = container;\n this.placeholder = options.placeholder || 'Search nodes or relationships...';\n this.onSearch = options.onSearch;\n this.onResultClick = options.onResultClick;\n this.init();\n }\n\n private init(): void {\n this.createSearchUI();\n this.addEventListeners();\n }\n\n private createSearchUI(): void {\n // Create search container\n this.searchContainer = document.createElement('div');\n this.searchContainer.className = 'f3d-search-container';\n Object.assign(this.searchContainer.style, {\n position: 'absolute',\n top: '20px',\n left: '175px', // Adjusted to make room for view toggle\n zIndex: '100',\n width: '320px'\n });\n\n // Create input wrapper\n const wrapper = document.createElement('div');\n wrapper.className = 'f3d-search-input-wrapper';\n Object.assign(wrapper.style, {\n position: 'relative',\n display: 'flex',\n alignItems: 'center'\n });\n\n // Add Search Icon (SVG)\n wrapper.innerHTML = `\n <svg class=\"f3d-search-icon\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" \n stroke-width=\"2\" style=\"position: absolute; left: 14px; z-index: 10; color: rgba(255, 255, 255, 0.5); pointer-events: none;\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.35-4.35\"></path>\n </svg>\n `;\n\n // Create input\n this.searchInput = document.createElement('input');\n this.searchInput.type = 'text';\n this.searchInput.className = 'f3d-search-input';\n this.searchInput.placeholder = this.placeholder;\n this.searchInput.autocomplete = 'off';\n Object.assign(this.searchInput.style, {\n width: '100%',\n padding: '12px 16px 12px 42px',\n background: 'rgba(255, 255, 255, 0.08)',\n backdropFilter: 'blur(20px)',\n webkitBackdropFilter: 'blur(20px)',\n border: '1px solid rgba(255, 255, 255, 0.12)',\n borderRadius: '12px',\n color: 'white',\n fontSize: '14px',\n fontFamily: 'inherit',\n outline: 'none',\n transition: 'all 0.2s ease'\n });\n\n // Add focus effect via JS (since we're adding styles inline)\n this.searchInput.addEventListener('focus', () => {\n if (this.searchInput) {\n this.searchInput.style.background = 'rgba(255, 255, 255, 0.12)';\n this.searchInput.style.borderColor = 'rgba(255, 153, 102, 0.5)';\n this.searchInput.style.boxShadow = '0 0 20px rgba(255, 153, 102, 0.15)';\n }\n });\n this.searchInput.addEventListener('blur', () => {\n if (this.searchInput) {\n this.searchInput.style.background = 'rgba(255, 255, 255, 0.08)';\n this.searchInput.style.borderColor = 'rgba(255, 255, 255, 0.12)';\n this.searchInput.style.boxShadow = 'none';\n }\n });\n\n // Create results dropdown\n this.searchResults = document.createElement('div');\n this.searchResults.className = 'f3d-search-results';\n Object.assign(this.searchResults.style, {\n position: 'absolute',\n top: '100%',\n left: '0',\n right: '0',\n marginTop: '8px',\n background: 'rgba(20, 20, 25, 0.95)',\n backdropFilter: 'blur(20px)',\n webkitBackdropFilter: 'blur(20px)',\n border: '1px solid rgba(255, 255, 255, 0.1)',\n borderRadius: '12px',\n maxHeight: '300px',\n overflowY: 'auto',\n display: 'none',\n boxShadow: '0 10px 40px rgba(0, 0, 0, 0.4)'\n });\n\n wrapper.appendChild(this.searchInput);\n this.searchContainer.appendChild(wrapper);\n this.searchContainer.appendChild(this.searchResults);\n this.container.appendChild(this.searchContainer);\n\n // Add some CSS for the list items\n const style = document.createElement('style');\n style.textContent = `\n .f3d-search-result-item {\n padding: 10px 14px;\n cursor: pointer;\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n transition: background 0.15s ease;\n }\n .f3d-search-result-item:hover {\n background: rgba(255, 153, 102, 0.15);\n }\n .f3d-search-result-item:last-child {\n border-bottom: none;\n }\n .f3d-result-label {\n color: white;\n font-size: 13px;\n font-weight: 500;\n margin-bottom: 2px;\n }\n .f3d-result-type {\n color: rgba(255, 153, 102, 0.8);\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n .f3d-result-relationship {\n color: rgba(255, 255, 255, 0.5);\n font-size: 11px;\n font-style: italic;\n }\n .f3d-no-results {\n padding: 14px;\n color: rgba(255, 255, 255, 0.4);\n font-size: 13px;\n text-align: center;\n }\n .f3d-search-section-header {\n padding: 8px 14px 6px;\n color: rgba(255, 255, 255, 0.3);\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 1px;\n font-weight: 600;\n background: rgba(0, 0, 0, 0.2);\n }\n .f3d-search-results::-webkit-scrollbar { width: 6px; }\n .f3d-search-results::-webkit-scrollbar-track { background: transparent; }\n .f3d-search-results::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 3px; }\n .f3d-search-results::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.25); }\n `;\n document.head.appendChild(style);\n }\n\n private addEventListeners(): void {\n if (!this.searchInput || !this.searchResults) return;\n\n this.searchInput.addEventListener('input', (e) => {\n const query = (e.target as HTMLInputElement).value;\n\n if (this.searchTimeout) window.clearTimeout(this.searchTimeout);\n this.searchTimeout = window.setTimeout(() => {\n this.performSearch(query);\n }, 150);\n });\n\n this.searchInput.addEventListener('focus', () => {\n if (this.searchInput && this.searchInput.value.length > 0) {\n this.searchResults!.style.display = 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (this.searchContainer && !this.searchContainer.contains(e.target as Node)) {\n if (this.searchResults) this.searchResults.style.display = 'none';\n }\n });\n }\n\n private performSearch(query: string): void {\n if (!this.searchResults) return;\n\n if (query.trim().length === 0) {\n this.searchResults.style.display = 'none';\n return;\n }\n\n const { nodeResults, edgeResults } = this.onSearch(query);\n\n if (nodeResults.length === 0 && edgeResults.length === 0) {\n this.searchResults.innerHTML = '<div class=\"f3d-no-results\">No results found</div>';\n this.searchResults.style.display = 'block';\n return;\n }\n\n let html = '';\n\n // Node results\n if (nodeResults.length > 0) {\n html += '<div class=\"f3d-search-section-header\">Nodes</div>';\n nodeResults.slice(0, 10).forEach(node => {\n const typeLabel = (node.type as string) || 'Node';\n html += `\n <div class=\"f3d-search-result-item\" data-node-id=\"${this.escapeHtml(node.id)}\">\n <div class=\"f3d-result-label\">${this.escapeHtml(node.label)}</div>\n <div class=\"f3d-result-type\">${this.escapeHtml(typeLabel)}</div>\n </div>\n `;\n });\n if (nodeResults.length > 10) {\n html += `<div class=\"f3d-no-results\">+ ${nodeResults.length - 10} more nodes</div>`;\n }\n }\n\n // Edge results\n if (edgeResults.length > 0) {\n html += '<div class=\"f3d-search-section-header\">Relationships</div>';\n edgeResults.slice(0, 5).forEach(({ edge, sourceNode, targetNode }) => {\n html += `\n <div class=\"f3d-search-result-item\" data-node-id=\"${this.escapeHtml(edge.source as string)}\">\n <div class=\"f3d-result-label\">${this.escapeHtml(sourceNode.label)} → ${this.escapeHtml(targetNode.label)}</div>\n <div class=\"f3d-result-relationship\">${this.escapeHtml((edge.relationship as string) || 'connected')}</div>\n </div>\n `;\n });\n if (edgeResults.length > 5) {\n html += `<div class=\"f3d-no-results\">+ ${edgeResults.length - 5} more relationships</div>`;\n }\n }\n\n this.searchResults.innerHTML = html;\n this.searchResults.style.display = 'block';\n\n // Add click handlers\n this.searchResults.querySelectorAll('.f3d-search-result-item').forEach(item => {\n item.addEventListener('click', () => {\n const nodeId = (item as HTMLElement).dataset.nodeId;\n if (nodeId) {\n this.onResultClick(nodeId);\n if (this.searchResults) this.searchResults.style.display = 'none';\n if (this.searchInput) {\n this.searchInput.blur();\n }\n }\n });\n });\n }\n\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n public dispose(): void {\n if (this.searchContainer && this.searchContainer.parentNode) {\n this.searchContainer.parentNode.removeChild(this.searchContainer);\n }\n }\n}\n","/**\n * View Toggle Manager\n * Handles the 2D/3D view toggle button with glassmorphic styling\n */\nexport type ViewMode = '2d' | '3d';\n\nexport class ViewToggleManager {\n private container: HTMLElement;\n private toggleContainer: HTMLElement | null = null;\n private currentMode: ViewMode = '3d';\n private onViewChange: (mode: ViewMode) => void;\n\n constructor(\n container: HTMLElement,\n options: {\n initialMode?: ViewMode;\n onViewChange: (mode: ViewMode) => void;\n }\n ) {\n this.container = container;\n this.currentMode = options.initialMode || '3d';\n this.onViewChange = options.onViewChange;\n this.init();\n }\n\n private init(): void {\n this.createToggleUI();\n }\n\n private createToggleUI(): void {\n // Create toggle container\n this.toggleContainer = document.createElement('div');\n this.toggleContainer.className = 'f3d-view-toggle';\n Object.assign(this.toggleContainer.style, {\n position: 'absolute',\n top: '20px',\n left: '20px',\n zIndex: '100',\n display: 'flex',\n gap: '0',\n background: 'rgba(255, 255, 255, 0.08)',\n backdropFilter: 'blur(20px)',\n WebkitBackdropFilter: 'blur(20px)',\n border: '1px solid rgba(255, 255, 255, 0.12)',\n borderRadius: '12px',\n padding: '5px',\n boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)'\n });\n\n // Create 2D button\n const btn2D = this.createButton('2D', '2d');\n const btn3D = this.createButton('3D', '3d');\n\n this.toggleContainer.appendChild(btn2D);\n this.toggleContainer.appendChild(btn3D);\n this.container.appendChild(this.toggleContainer);\n\n // Update initial state\n this.updateButtonStates();\n\n // Add CSS for hover/active states\n const style = document.createElement('style');\n style.textContent = `\n .f3d-view-btn {\n padding: 8px 16px;\n background: transparent;\n border: none;\n color: rgba(255, 255, 255, 0.5);\n font-size: 12px;\n font-weight: 600;\n font-family: inherit;\n letter-spacing: 0.5px;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: 8px;\n min-width: 44px;\n }\n .f3d-view-btn:hover {\n color: rgba(255, 255, 255, 0.8);\n }\n .f3d-view-btn.active {\n background: linear-gradient(135deg, rgba(255, 153, 102, 0.3), rgba(255, 102, 153, 0.2));\n color: white;\n box-shadow: 0 0 15px rgba(255, 153, 102, 0.2);\n }\n .f3d-view-btn:focus {\n outline: none;\n }\n `;\n document.head.appendChild(style);\n }\n\n private createButton(label: string, mode: ViewMode): HTMLButtonElement {\n const btn = document.createElement('button');\n btn.className = 'f3d-view-btn';\n btn.dataset.mode = mode;\n btn.innerHTML = this.getIcon(mode) + `<span style=\"margin-left: 4px;\">${label}</span>`;\n btn.style.display = 'flex';\n btn.style.alignItems = 'center';\n btn.style.justifyContent = 'center';\n\n btn.addEventListener('click', () => {\n if (this.currentMode !== mode) {\n this.currentMode = mode;\n this.updateButtonStates();\n this.onViewChange(mode);\n }\n });\n\n return btn;\n }\n\n private getIcon(mode: ViewMode): string {\n if (mode === '2d') {\n // Grid/2D icon\n return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"></rect>\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"></rect>\n <rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"></rect>\n <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"></rect>\n </svg>`;\n } else {\n // Cube/3D icon\n return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\"></path>\n <polyline points=\"3.27 6.96 12 12.01 20.73 6.96\"></polyline>\n <line x1=\"12\" y1=\"22.08\" x2=\"12\" y2=\"12\"></line>\n </svg>`;\n }\n }\n\n private updateButtonStates(): void {\n if (!this.toggleContainer) return;\n\n const buttons = this.toggleContainer.querySelectorAll('.f3d-view-btn');\n buttons.forEach((btn) => {\n const mode = (btn as HTMLElement).dataset.mode as ViewMode;\n if (mode === this.currentMode) {\n btn.classList.add('active');\n } else {\n btn.classList.remove('active');\n }\n });\n }\n\n public setMode(mode: ViewMode): void {\n if (this.currentMode !== mode) {\n this.currentMode = mode;\n this.updateButtonStates();\n }\n }\n\n public getMode(): ViewMode {\n return this.currentMode;\n }\n\n public dispose(): void {\n if (this.toggleContainer && this.toggleContainer.parentNode) {\n this.toggleContainer.parentNode.removeChild(this.toggleContainer);\n }\n }\n}\n","import type { NodeData, Edge, InternalNode } from '../utils/types';\n\n/**\n * 2D Node representation\n */\ninterface Node2D {\n id: string;\n label: string;\n x: number;\n y: number;\n vx: number;\n vy: number;\n color: number;\n radius: number;\n data: NodeData;\n}\n\n/**\n * 2D Edge representation\n */\ninterface Edge2D {\n source: string;\n target: string;\n relationship?: string;\n data: Edge;\n}\n\n/**\n * Transform state for pan/zoom\n */\ninterface Transform {\n x: number;\n y: number;\n scale: number;\n}\n\n/**\n * ForceGraph2D Options\n */\nexport interface ForceGraph2DOptions {\n backgroundColor?: string;\n gridColor?: string;\n nodeRadius?: number;\n edgeColor?: string;\n edgeOpacity?: number;\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n onNodeClick?: (node: NodeData) => void;\n onNodeHover?: (node: NodeData | null) => void;\n onEdgeHover?: (edge: Edge | null, event?: MouseEvent) => void;\n onEdgeClick?: (edge: Edge) => void;\n}\n\nconst DEFAULT_2D_OPTIONS: Required<Omit<ForceGraph2DOptions, 'onNodeClick' | 'onNodeHover' | 'onEdgeHover' | 'onEdgeClick'>> = {\n backgroundColor: '#0a0a0a',\n gridColor: 'rgba(255, 255, 255, 0.03)',\n nodeRadius: 24,\n edgeColor: 'rgba(255, 255, 255, 0.15)',\n edgeOpacity: 0.4,\n repulsionStrength: 5000, // Strong repulsion for spread out layout\n attractionStrength: 0.001, // Very low attraction\n damping: 0.85 // Fast energy dissipation\n};\n\n/**\n * ForceGraph2D\n * 2D Canvas-based force-directed graph renderer with premium aesthetics\n */\nexport class ForceGraph2D {\n private container: HTMLElement;\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n private options: Required<Omit<ForceGraph2DOptions, 'onNodeClick' | 'onNodeHover' | 'onEdgeHover' | 'onEdgeClick'>> & ForceGraph2DOptions;\n\n // Data\n private nodes: Map<string, Node2D> = new Map();\n private edges: Edge2D[] = [];\n private nodeIdToIndex: Map<string, number> = new Map();\n\n // Transform state\n private transform: Transform = { x: 0, y: 0, scale: 1 };\n\n // Interaction state\n private isDragging: boolean = false;\n private isPanning: boolean = false;\n private draggedNode: Node2D | null = null;\n private hoveredNode: Node2D | null = null;\n private hoveredEdge: Edge2D | null = null;\n private lastMousePos: { x: number; y: number } = { x: 0, y: 0 };\n private dragStartPos: { x: number; y: number } = { x: 0, y: 0 }; // Track initial click position\n private selectedNode: Node2D | null = null;\n\n // Animation\n private animationId: number | null = null;\n private isSimulating: boolean = true;\n\n // Resize handler\n private resizeHandler: () => void;\n\n constructor(container: HTMLElement, options: ForceGraph2DOptions = {}) {\n this.container = container;\n this.options = { ...DEFAULT_2D_OPTIONS, ...options };\n\n // Create canvas\n this.canvas = document.createElement('canvas');\n this.canvas.style.position = 'absolute';\n this.canvas.style.top = '0';\n this.canvas.style.left = '0';\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.canvas.style.cursor = 'grab';\n container.appendChild(this.canvas);\n\n const ctx = this.canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get 2D context');\n }\n this.ctx = ctx;\n\n // Setup\n this.resizeHandler = this.handleResize.bind(this);\n window.addEventListener('resize', this.resizeHandler);\n this.handleResize();\n\n // Center transform\n this.transform.x = this.canvas.width / 2;\n this.transform.y = this.canvas.height / 2;\n\n // Setup interactions\n this.setupInteractions();\n\n // Start render loop\n this.startAnimation();\n }\n\n private handleResize(): void {\n const rect = this.container.getBoundingClientRect();\n const dpr = window.devicePixelRatio || 1;\n this.canvas.width = rect.width * dpr;\n this.canvas.height = rect.height * dpr;\n this.ctx.scale(dpr, dpr);\n }\n\n private setupInteractions(): void {\n // Mouse wheel for zoom\n this.canvas.addEventListener('wheel', (e) => {\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n\n const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;\n const newScale = Math.max(0.1, Math.min(5, this.transform.scale * zoomFactor));\n\n // Zoom towards mouse position\n const scaleChange = newScale / this.transform.scale;\n this.transform.x = mouseX - (mouseX - this.transform.x) * scaleChange;\n this.transform.y = mouseY - (mouseY - this.transform.y) * scaleChange;\n this.transform.scale = newScale;\n });\n\n // Mouse down\n this.canvas.addEventListener('mousedown', (e) => {\n const rect = this.canvas.getBoundingClientRect();\n const screenX = e.clientX - rect.left;\n const screenY = e.clientY - rect.top;\n const pos = this.screenToWorld(screenX, screenY);\n const node = this.findNodeAt(pos.x, pos.y);\n\n // Always save start position for click detection\n this.dragStartPos = { x: e.clientX, y: e.clientY };\n\n if (node) {\n this.isDragging = true;\n this.draggedNode = node;\n this.canvas.style.cursor = 'grabbing';\n // Restart simulation briefly when dragging\n this.isSimulating = true;\n } else {\n this.isPanning = true;\n this.canvas.style.cursor = 'grabbing';\n }\n\n this.lastMousePos = { x: e.clientX, y: e.clientY };\n });\n\n // Mouse move\n this.canvas.addEventListener('mousemove', (e) => {\n const rect = this.canvas.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const worldPos = this.screenToWorld(mouseX, mouseY);\n\n if (this.isDragging && this.draggedNode) {\n this.draggedNode.x = worldPos.x;\n this.draggedNode.y = worldPos.y;\n this.draggedNode.vx = 0;\n this.draggedNode.vy = 0;\n } else if (this.isPanning) {\n const dx = e.clientX - this.lastMousePos.x;\n const dy = e.clientY - this.lastMousePos.y;\n this.transform.x += dx;\n this.transform.y += dy;\n this.lastMousePos = { x: e.clientX, y: e.clientY };\n } else {\n // Hover detection - check nodes first, then edges\n const node = this.findNodeAt(worldPos.x, worldPos.y);\n if (node !== this.hoveredNode) {\n this.hoveredNode = node;\n if (node) {\n // Hovering a node - clear edge hover\n if (this.hoveredEdge) {\n this.hoveredEdge = null;\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(null);\n }\n }\n this.canvas.style.cursor = 'pointer';\n if (this.options.onNodeHover) {\n this.options.onNodeHover(node.data);\n }\n } else {\n if (this.options.onNodeHover) {\n this.options.onNodeHover(null);\n }\n }\n }\n\n // Check edge hover if not hovering a node\n if (!node) {\n const edge = this.findEdgeAt(worldPos.x, worldPos.y);\n if (edge !== this.hoveredEdge) {\n this.hoveredEdge = edge;\n this.canvas.style.cursor = edge ? 'pointer' : 'grab';\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(edge ? edge.data : null, e);\n }\n }\n }\n }\n });\n\n // Mouse up\n this.canvas.addEventListener('mouseup', (e) => {\n const dx = Math.abs(e.clientX - this.dragStartPos.x);\n const dy = Math.abs(e.clientY - this.dragStartPos.y);\n const wasClick = dx < 5 && dy < 5;\n\n if (this.isDragging && this.draggedNode) {\n // Node click\n if (wasClick && this.options.onNodeClick) {\n this.selectedNode = this.draggedNode;\n this.options.onNodeClick(this.draggedNode.data);\n }\n } else if (wasClick) {\n // Check if clicked on an edge - ignore if we notably moved (covered by wasClick)\n const rect = this.canvas.getBoundingClientRect();\n const worldPos = this.screenToWorld(e.clientX - rect.left, e.clientY - rect.top);\n const edge = this.findEdgeAt(worldPos.x, worldPos.y);\n if (edge && this.options.onEdgeClick) {\n this.options.onEdgeClick(edge.data);\n }\n }\n\n this.isDragging = false;\n this.isPanning = false;\n this.draggedNode = null;\n this.canvas.style.cursor = this.hoveredNode ? 'pointer' : 'grab';\n });\n\n // Mouse leave\n this.canvas.addEventListener('mouseleave', () => {\n this.isDragging = false;\n this.isPanning = false;\n this.draggedNode = null;\n this.hoveredNode = null;\n this.canvas.style.cursor = 'grab';\n });\n }\n\n private screenToWorld(screenX: number, screenY: number): { x: number; y: number } {\n return {\n x: (screenX - this.transform.x) / this.transform.scale,\n y: (screenY - this.transform.y) / this.transform.scale\n };\n }\n\n private findNodeAt(x: number, y: number): Node2D | null {\n for (const node of this.nodes.values()) {\n const dx = node.x - x;\n const dy = node.y - y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < node.radius) {\n return node;\n }\n }\n return null;\n }\n\n private findEdgeAt(x: number, y: number): Edge2D | null {\n const threshold = 12; // Increased distance threshold for easier click detection\n\n for (const edge of this.edges) {\n const source = this.nodes.get(edge.source);\n const target = this.nodes.get(edge.target);\n if (!source || !target) continue;\n\n // Calculate distance from point to line segment\n const dx = target.x - source.x;\n const dy = target.y - source.y;\n const lengthSq = dx * dx + dy * dy;\n\n if (lengthSq === 0) continue;\n\n // Calculate projection of point onto line\n const t = Math.max(0, Math.min(1, ((x - source.x) * dx + (y - source.y) * dy) / lengthSq));\n const projX = source.x + t * dx;\n const projY = source.y + t * dy;\n\n // Distance from point to projection\n const distX = x - projX;\n const distY = y - projY;\n const dist = Math.sqrt(distX * distX + distY * distY);\n\n if (dist < threshold) {\n return edge;\n }\n }\n return null;\n }\n\n private startAnimation(): void {\n const animate = () => {\n if (this.isSimulating) {\n this.simulate();\n }\n this.render();\n this.animationId = requestAnimationFrame(animate);\n };\n animate();\n }\n\n private simulate(): void {\n const nodes = Array.from(this.nodes.values());\n const n = nodes.length;\n if (n === 0) return;\n\n const minDistance = 60; // Minimum distance between nodes\n const maxVelocity = 5; // Cap velocity to prevent runaway\n let totalEnergy = 0;\n\n // Repulsion between all nodes\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n const nodeA = nodes[i];\n const nodeB = nodes[j];\n let dx = nodeB.x - nodeA.x;\n let dy = nodeB.y - nodeA.y;\n let dist = Math.sqrt(dx * dx + dy * dy);\n\n // Only apply repulsion if nodes are closer than minimum distance\n if (dist < minDistance * 3) {\n if (dist < 1) dist = 1;\n\n // Stronger repulsion at very close range, falls off quickly\n const force = this.options.repulsionStrength / (dist * dist);\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n\n nodeA.vx -= fx;\n nodeA.vy -= fy;\n nodeB.vx += fx;\n nodeB.vy += fy;\n }\n }\n }\n\n // Attraction along edges - target distance based on node radius\n const targetDist = 80; // Ideal edge length\n for (const edge of this.edges) {\n const source = this.nodes.get(edge.source);\n const target = this.nodes.get(edge.target);\n if (!source || !target) continue;\n\n let dx = target.x - source.x;\n let dy = target.y - source.y;\n let dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < 1) dist = 1;\n\n // Spring-like attraction: pull if too far, push if too close\n const displacement = dist - targetDist;\n const force = displacement * this.options.attractionStrength;\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n\n source.vx += fx;\n source.vy += fy;\n target.vx -= fx;\n target.vy -= fy;\n }\n\n // Apply velocity with damping and calculate total energy\n for (const node of nodes) {\n if (this.draggedNode === node) continue;\n\n // Apply damping\n node.vx *= this.options.damping;\n node.vy *= this.options.damping;\n\n // Cap velocity\n const speed = Math.sqrt(node.vx * node.vx + node.vy * node.vy);\n if (speed > maxVelocity) {\n node.vx = (node.vx / speed) * maxVelocity;\n node.vy = (node.vy / speed) * maxVelocity;\n }\n\n // Update position\n node.x += node.vx;\n node.y += node.vy;\n\n // Track total kinetic energy\n totalEnergy += node.vx * node.vx + node.vy * node.vy;\n }\n\n // Auto-stop simulation when energy is very low (system at rest)\n if (totalEnergy < 0.01 && !this.draggedNode) {\n this.isSimulating = false;\n }\n }\n\n private render(): void {\n const ctx = this.ctx;\n const width = this.canvas.width / (window.devicePixelRatio || 1);\n const height = this.canvas.height / (window.devicePixelRatio || 1);\n\n // Clear canvas\n ctx.fillStyle = this.options.backgroundColor;\n ctx.fillRect(0, 0, width, height);\n\n // Draw grid\n this.renderGrid(width, height);\n\n // Apply transform\n ctx.save();\n ctx.translate(this.transform.x, this.transform.y);\n ctx.scale(this.transform.scale, this.transform.scale);\n\n // Draw edges\n this.renderEdges();\n\n // Draw nodes\n this.renderNodes();\n\n ctx.restore();\n }\n\n private renderGrid(width: number, height: number): void {\n const ctx = this.ctx;\n const gridSize = 40 * this.transform.scale;\n const dotRadius = 1.5;\n\n // Calculate grid offset based on transform\n const offsetX = this.transform.x % gridSize;\n const offsetY = this.transform.y % gridSize;\n\n ctx.fillStyle = this.options.gridColor;\n\n for (let x = offsetX; x < width; x += gridSize) {\n for (let y = offsetY; y < height; y += gridSize) {\n ctx.beginPath();\n ctx.arc(x, y, dotRadius, 0, Math.PI * 2);\n ctx.fill();\n }\n }\n }\n\n private renderEdges(): void {\n const ctx = this.ctx;\n\n for (const edge of this.edges) {\n const source = this.nodes.get(edge.source);\n const target = this.nodes.get(edge.target);\n if (!source || !target) continue;\n\n const isHovered = edge === this.hoveredEdge;\n\n // Draw edge line with gradient\n const gradient = ctx.createLinearGradient(source.x, source.y, target.x, target.y);\n\n if (isHovered) {\n gradient.addColorStop(0, 'rgba(255, 153, 102, 0.8)');\n gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');\n gradient.addColorStop(1, 'rgba(102, 153, 255, 0.8)');\n ctx.lineWidth = 3.0;\n } else {\n gradient.addColorStop(0, 'rgba(255, 153, 102, 0.3)');\n gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.15)');\n gradient.addColorStop(1, 'rgba(102, 153, 255, 0.3)');\n ctx.lineWidth = 1.5;\n }\n\n ctx.beginPath();\n ctx.moveTo(source.x, source.y);\n ctx.lineTo(target.x, target.y);\n ctx.strokeStyle = gradient;\n ctx.stroke();\n }\n }\n\n private renderNodes(): void {\n const ctx = this.ctx;\n\n for (const node of this.nodes.values()) {\n const isHovered = node === this.hoveredNode;\n const isSelected = node === this.selectedNode;\n const isConnectedToHoveredEdge = this.hoveredEdge &&\n (node.data.id === this.hoveredEdge.source || node.data.id === this.hoveredEdge.target);\n\n const radius = node.radius * (isHovered ? 1.1 : 1);\n\n // Outer glow\n if (isHovered || isSelected || isConnectedToHoveredEdge) {\n const glowGradient = ctx.createRadialGradient(\n node.x, node.y, radius * 0.5,\n node.x, node.y, radius * 2\n );\n\n const alpha = (isHovered || isSelected) ? 0.4 : 0.25;\n glowGradient.addColorStop(0, `rgba(255, 153, 102, ${alpha})`);\n glowGradient.addColorStop(1, 'rgba(255, 153, 102, 0)');\n\n ctx.fillStyle = glowGradient;\n ctx.beginPath();\n ctx.arc(node.x, node.y, radius * 2, 0, Math.PI * 2);\n ctx.fill();\n }\n\n // Node background with gradient\n const nodeGradient = ctx.createRadialGradient(\n node.x - radius * 0.3, node.y - radius * 0.3, 0,\n node.x, node.y, radius\n );\n\n // Convert hex color to RGB\n const r = (node.color >> 16) & 255;\n const g = (node.color >> 8) & 255;\n const b = node.color & 255;\n\n nodeGradient.addColorStop(0, `rgba(${Math.min(255, r + 60)}, ${Math.min(255, g + 60)}, ${Math.min(255, b + 60)}, 0.95)`);\n nodeGradient.addColorStop(0.7, `rgba(${r}, ${g}, ${b}, 0.9)`);\n nodeGradient.addColorStop(1, `rgba(${Math.max(0, r - 40)}, ${Math.max(0, g - 40)}, ${Math.max(0, b - 40)}, 0.85)`);\n\n // Draw node circle\n ctx.beginPath();\n ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);\n ctx.fillStyle = nodeGradient;\n ctx.fill();\n\n // Subtle border\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';\n ctx.lineWidth = 1;\n ctx.stroke();\n\n // Inner highlight\n ctx.beginPath();\n ctx.arc(node.x - radius * 0.25, node.y - radius * 0.25, radius * 0.3, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.fill();\n\n // Draw label\n ctx.fillStyle = 'white';\n ctx.font = '600 11px Inter, -apple-system, BlinkMacSystemFont, sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Truncate label if too long\n const maxWidth = radius * 1.6;\n let label = node.label;\n let textWidth = ctx.measureText(label).width;\n if (textWidth > maxWidth) {\n while (textWidth > maxWidth && label.length > 3) {\n label = label.slice(0, -1);\n textWidth = ctx.measureText(label + '...').width;\n }\n label += '...';\n }\n\n // Text shadow for better readability\n ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';\n ctx.shadowBlur = 3;\n ctx.fillText(label, node.x, node.y);\n ctx.shadowBlur = 0;\n }\n }\n\n /**\n * Sets the graph data\n */\n public setData(data: { nodes: NodeData[]; edges: Edge[] }): void {\n this.nodes.clear();\n this.edges = [];\n this.nodeIdToIndex.clear();\n\n // Create nodes with positions\n data.nodes.forEach((nodeData, index) => {\n const pos = nodeData.position || {\n x: (Math.random() - 0.5) * 300,\n y: (Math.random() - 0.5) * 300\n };\n\n const node: Node2D = {\n id: nodeData.id,\n label: nodeData.label,\n x: pos.x,\n y: pos.y,\n vx: 0,\n vy: 0,\n color: nodeData.color || 0xff9966, // Match 3D tangerine color\n radius: this.options.nodeRadius,\n data: nodeData\n };\n\n this.nodes.set(nodeData.id, node);\n this.nodeIdToIndex.set(nodeData.id, index);\n });\n\n // Create edges\n this.edges = data.edges.map(edge => ({\n source: edge.source,\n target: edge.target,\n relationship: edge.relationship,\n data: edge\n }));\n }\n\n /**\n * Adds a node\n */\n public addNode(nodeData: NodeData): void {\n const pos = nodeData.position || {\n x: (Math.random() - 0.5) * 300,\n y: (Math.random() - 0.5) * 300\n };\n\n const node: Node2D = {\n id: nodeData.id,\n label: nodeData.label,\n x: pos.x,\n y: pos.y,\n vx: 0,\n vy: 0,\n color: nodeData.color || 0xff9966, // Match 3D tangerine color\n radius: this.options.nodeRadius,\n data: nodeData\n };\n\n this.nodes.set(nodeData.id, node);\n }\n\n /**\n * Adds an edge\n */\n public addEdge(edge: Edge): void {\n this.edges.push({\n source: edge.source,\n target: edge.target,\n relationship: edge.relationship,\n data: edge\n });\n }\n\n /**\n * Removes a node\n */\n public removeNode(nodeId: string): void {\n this.nodes.delete(nodeId);\n this.edges = this.edges.filter(e => e.source !== nodeId && e.target !== nodeId);\n }\n\n /**\n * Gets a node by ID\n */\n public getNode(nodeId: string): Node2D | undefined {\n return this.nodes.get(nodeId);\n }\n\n /**\n * Gets all nodes\n */\n public getAllNodes(): NodeData[] {\n return Array.from(this.nodes.values()).map(n => n.data);\n }\n\n /**\n * Gets node count\n */\n public getNodeCount(): number {\n return this.nodes.size;\n }\n\n /**\n * Gets edge count\n */\n public getEdgeCount(): number {\n return this.edges.length;\n }\n\n /**\n * Focuses on a node\n */\n public focusOnNode(nodeId: string): void {\n const node = this.nodes.get(nodeId);\n if (!node) return;\n\n const targetX = this.canvas.width / 2 / (window.devicePixelRatio || 1) - node.x * this.transform.scale;\n const targetY = this.canvas.height / 2 / (window.devicePixelRatio || 1) - node.y * this.transform.scale;\n\n // Animate to position\n const startX = this.transform.x;\n const startY = this.transform.y;\n const duration = 500;\n const startTime = performance.now();\n\n const animate = () => {\n const elapsed = performance.now() - startTime;\n const progress = Math.min(elapsed / duration, 1);\n const eased = 1 - Math.pow(1 - progress, 3);\n\n this.transform.x = startX + (targetX - startX) * eased;\n this.transform.y = startY + (targetY - startY) * eased;\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n } else {\n this.selectedNode = node;\n }\n };\n\n animate();\n }\n\n /**\n * Updates node positions from 3D data\n */\n public syncFrom3D(nodesMap: Map<string, InternalNode>): void {\n nodesMap.forEach((node3d, id) => {\n const node2d = this.nodes.get(id);\n if (node2d) {\n // Use x and y from 3D, scale up for better spacing in 2D\n node2d.x = node3d.position.x * 3; // Scale for visibility\n node2d.y = node3d.position.y * 3;\n node2d.vx = 0;\n node2d.vy = 0;\n }\n });\n // Positions from 3D are already stable, so stop simulation\n this.isSimulating = false;\n }\n\n /**\n * Gets 2D positions for syncing to 3D\n */\n public getPositions(): Map<string, { x: number; y: number }> {\n const positions = new Map<string, { x: number; y: number }>();\n this.nodes.forEach((node, id) => {\n positions.set(id, { x: node.x, y: node.y });\n });\n return positions;\n }\n\n /**\n * Show/hide the canvas\n */\n public show(): void {\n this.canvas.style.display = 'block';\n }\n\n public hide(): void {\n this.canvas.style.display = 'none';\n }\n\n /**\n * Updates physics parameters in real-time\n */\n public setPhysicsParams(params: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number\n }): void {\n if (params.repulsionStrength !== undefined) {\n this.options.repulsionStrength = params.repulsionStrength;\n }\n if (params.attractionStrength !== undefined) {\n this.options.attractionStrength = params.attractionStrength;\n }\n if (params.damping !== undefined) {\n this.options.damping = params.damping;\n }\n // Restart simulation to apply new params\n this.isSimulating = true;\n }\n\n /**\n * Dispose resources\n */\n public dispose(): void {\n if (this.animationId) {\n cancelAnimationFrame(this.animationId);\n }\n window.removeEventListener('resize', this.resizeHandler);\n if (this.canvas.parentNode) {\n this.canvas.parentNode.removeChild(this.canvas);\n }\n }\n}\n","import type {\n ForceGraph3DOptions,\n GraphData,\n NodeData,\n Edge,\n InternalNode,\n EventType,\n EventCallback\n} from './utils/types';\nimport { DEFAULT_OPTIONS } from './utils/types';\nimport { validateContainer } from './utils/ContainerManager';\nimport { validateNodeData, validateEdgeData, validateNodeId } from './utils/validation';\n\n// Core components\nimport { SceneManager } from './core/SceneManager';\nimport { NodeManager } from './core/NodeManager';\nimport { EdgeManager } from './core/EdgeManager';\nimport { GraphEngine } from './core/GraphEngine';\nimport { RendererManager } from './core/RendererManager';\n\n// Factories\nimport { MaterialFactory } from './factory/MaterialFactory';\nimport { NodeFactory } from './factory/NodeFactory';\nimport { EdgeFactory } from './factory/EdgeFactory';\n\n// Performance\nimport { LODManager } from './performance/LODManager';\nimport { FrustumCuller } from './performance/FrustumCuller';\n\n// Interaction\nimport { RaycasterManager } from './interaction/RaycasterManager';\nimport type { EdgeHoverInfo } from './interaction/RaycasterManager';\nimport { PanelManager } from './interaction/PanelManager';\nimport { EdgePanelManager } from './interaction/EdgePanelManager';\nimport { EdgeTooltipManager } from './interaction/EdgeTooltipManager';\nimport { SearchManager } from './interaction/SearchManager';\nimport { ViewToggleManager, type ViewMode } from './interaction/ViewToggleManager';\n\n// 2D Renderer\nimport { ForceGraph2D } from './core/ForceGraph2D';\n\ndeclare const __DEV__: boolean;\n\n/**\n * ForceGraph3D\n * Main class for the 3D force-directed graph library\n */\nexport class ForceGraph3D {\n // Options\n private options: ForceGraph3DOptions;\n private container: HTMLElement;\n\n // Core components\n private sceneManager: SceneManager;\n private nodeManager: NodeManager;\n private edgeManager: EdgeManager;\n private graphEngine: GraphEngine;\n private rendererManager: RendererManager;\n\n // Factories\n private materialFactory: MaterialFactory;\n private nodeFactory: NodeFactory;\n private edgeFactory: EdgeFactory;\n\n // Performance\n private lodManager: LODManager;\n private frustumCuller: FrustumCuller;\n\n // Interaction\n private raycasterManager: RaycasterManager;\n private panelManager: PanelManager;\n private edgePanelManager: EdgePanelManager;\n private edgeTooltipManager: EdgeTooltipManager;\n private searchManager: SearchManager | null = null;\n private viewToggleManager: ViewToggleManager | null = null;\n\n // 2D Renderer\n private forceGraph2D: ForceGraph2D | null = null;\n\n // Event system\n private eventCallbacks: Map<EventType, EventCallback[]> = new Map();\n\n // State\n private initialized: boolean = false;\n private devControls: HTMLElement | null = null;\n private viewMode: ViewMode = '3d';\n private graphData: GraphData | null = null; // Store graph data for view switching\n\n constructor(container?: HTMLElement | null, options: ForceGraph3DOptions = {}) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.container = validateContainer(container);\n\n // Initialize factories\n this.materialFactory = new MaterialFactory();\n this.nodeFactory = new NodeFactory(\n this.materialFactory,\n this.options.nodeRadius ?? DEFAULT_OPTIONS.nodeRadius,\n this.options.lodSegments ?? DEFAULT_OPTIONS.lodSegments,\n this.options.defaultNodeColor ?? DEFAULT_OPTIONS.defaultNodeColor\n );\n this.edgeFactory = new EdgeFactory(\n this.materialFactory,\n this.options.edgeColor ?? DEFAULT_OPTIONS.edgeColor,\n this.options.edgeOpacity ?? DEFAULT_OPTIONS.edgeOpacity\n );\n\n // Initialize scene\n this.sceneManager = new SceneManager(this.container, this.options);\n\n // Initialize performance managers\n this.lodManager = new LODManager(\n this.sceneManager.camera,\n this.options.lodDistances ?? DEFAULT_OPTIONS.lodDistances,\n this.options.enableLOD ?? DEFAULT_OPTIONS.enableLOD\n );\n this.frustumCuller = new FrustumCuller(\n this.sceneManager.camera,\n this.options.enableEdgeCulling ?? DEFAULT_OPTIONS.enableEdgeCulling\n );\n\n // Initialize node/edge managers\n this.nodeManager = new NodeManager(this.sceneManager, this.nodeFactory);\n this.edgeManager = new EdgeManager(this.sceneManager, this.nodeManager, this.edgeFactory);\n\n // Initialize graph engine\n this.graphEngine = new GraphEngine(\n this.nodeManager.getAllNodes(),\n this.edgeManager.getAllEdges(),\n {\n repulsionStrength: this.options.repulsionStrength,\n attractionStrength: this.options.attractionStrength,\n damping: this.options.damping,\n useBarnesHut: this.options.useBarnesHut,\n barnesHutTheta: this.options.barnesHutTheta,\n }\n );\n\n // Initialize renderer\n this.rendererManager = new RendererManager(\n this.sceneManager,\n () => this.onSimulate(),\n () => this.onRender(),\n this.options.targetFPS ?? DEFAULT_OPTIONS.targetFPS\n );\n\n // Initialize interaction\n this.raycasterManager = new RaycasterManager(this.sceneManager, this.container);\n this.panelManager = new PanelManager(this.container);\n this.edgePanelManager = new EdgePanelManager(this.container);\n this.edgeTooltipManager = new EdgeTooltipManager();\n\n // Set up edge panel node click callback for navigation\n this.edgePanelManager.setNodeClickCallback((nodeId: string) => {\n this.edgePanelManager.hide();\n this.focusOnNode(nodeId);\n setTimeout(() => {\n this.showNodePanel(nodeId);\n }, 400);\n });\n\n // Initialize search\n if (this.options.showSearch !== false) {\n this.searchManager = new SearchManager(this.container, {\n placeholder: this.options.searchPlaceholder,\n onSearch: (query: string) => ({\n nodeResults: this.searchNodes(query),\n edgeResults: this.searchEdges(query)\n }),\n onResultClick: (nodeId: string) => {\n this.focusOnNode(nodeId);\n setTimeout(() => {\n this.showNodePanel(nodeId);\n }, 400);\n }\n });\n }\n\n // Initialize view toggle\n if (this.options.showViewToggle !== false) {\n this.viewMode = (this.options.initialViewMode as ViewMode) || '3d';\n this.viewToggleManager = new ViewToggleManager(this.container, {\n initialMode: this.viewMode,\n onViewChange: (mode: ViewMode) => {\n this.switchView(mode);\n }\n });\n }\n\n // Setup callbacks\n this.setupCallbacks();\n\n // Dev mode controls\n if (typeof __DEV__ !== 'undefined' && __DEV__) {\n this.createDevControls();\n }\n\n // Start rendering\n this.rendererManager.start();\n this.initialized = true;\n\n // Emit ready event\n this.emit('ready');\n }\n\n /**\n * Sets up internal callbacks\n */\n private setupCallbacks(): void {\n // Node click callback\n this.raycasterManager.setClickCallback((nodeData) => {\n this.onNodeClick(nodeData);\n });\n\n // Node hover callback\n if (this.options.onNodeHover) {\n this.raycasterManager.setHoverCallback(this.options.onNodeHover);\n }\n\n // Panel expand callback\n this.panelManager.setExpandCallback((nodeId, depth) => {\n this.expandNode(nodeId, depth);\n });\n\n // Custom panel template\n if (this.options.panelTemplate) {\n this.panelManager.setPanelTemplate(this.options.panelTemplate);\n }\n\n // Custom panel styles\n if (this.options.panelStyles) {\n this.panelManager.setPanelStyles(this.options.panelStyles);\n }\n\n // Edge hover callback\n this.raycasterManager.setEdgeHoverCallback((info: EdgeHoverInfo | null) => {\n this.onEdgeHover(info);\n });\n\n // Edge click callback\n this.raycasterManager.setEdgeClickCallback((info: EdgeHoverInfo) => {\n this.onEdgeClick(info);\n });\n }\n\n /**\n * Handles edge hover\n */\n private onEdgeHover(info: EdgeHoverInfo | null): void {\n if (info) {\n // Highlight the edge\n this.edgeManager.highlightEdge(info.edge.source, info.edge.target);\n\n // Show tooltip\n const rect = this.container.getBoundingClientRect();\n const mouseX = rect.left + rect.width / 2;\n const mouseY = rect.top + rect.height / 2;\n this.edgeTooltipManager.show(info.edge, info.sourceNode, info.targetNode, mouseX, mouseY);\n\n // Call user callback\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(info.edge, info.sourceNode, info.targetNode);\n }\n this.emit('edgeHover', info.edge, info.sourceNode, info.targetNode);\n } else {\n // Unhighlight\n this.edgeManager.unhighlightCurrentEdge();\n this.edgeTooltipManager.hide();\n\n if (this.options.onEdgeHover) {\n this.options.onEdgeHover(null, null, null);\n }\n this.emit('edgeHover', null, null, null);\n }\n }\n\n /**\n * Handles node click\n */\n private onNodeClick(nodeData: NodeData): void {\n // Hide edge panel if visible\n this.edgePanelManager.hide();\n\n // Get neighbors\n const neighborIds = this.edgeManager.getNeighborIds(nodeData.id);\n const neighbors: NodeData[] = neighborIds\n .map(id => this.nodeManager.getNode(id))\n .filter((n): n is InternalNode => n !== undefined);\n\n // Show panel\n if (this.options.showPanel !== false) {\n this.panelManager.show(nodeData, neighbors);\n }\n\n // Call user callback\n if (this.options.onNodeClick) {\n this.options.onNodeClick(nodeData);\n }\n\n this.emit('nodeClick', nodeData);\n }\n\n /**\n * Handles edge click\n */\n private onEdgeClick(info: EdgeHoverInfo): void {\n // Hide node panel if visible\n this.panelManager.hide();\n\n // Hide tooltip\n this.edgeTooltipManager.hide();\n\n // Highlight the edge\n this.edgeManager.highlightEdge(info.edge.source, info.edge.target);\n\n // Show edge panel with relationship info\n this.edgePanelManager.show(info.edge, info.sourceNode, info.targetNode);\n\n // Focus camera on both nodes\n this.focusOnEdge(info.edge.source, info.edge.target);\n\n // Emit event\n this.emit('edgeClick', info.edge, info.sourceNode, info.targetNode);\n }\n\n /**\n * Called every simulation step\n */\n private onSimulate(): void {\n // Run physics simulation\n this.graphEngine.simulate();\n\n // Update node positions in the scene\n for (const [nodeId, node] of this.nodeManager.getAllNodes()) {\n this.nodeManager.updateNodePosition(nodeId, node.position);\n\n // Update LOD based on distance from camera\n if (this.options.enableLOD) {\n const newLodLevel = this.lodManager.getLODLevel(node.position);\n this.nodeManager.updateNodeLOD(nodeId, newLodLevel);\n }\n }\n\n // Update edge positions\n this.edgeManager.updateEdgePositions();\n }\n\n /**\n * Called every render frame\n */\n private onRender(): void {\n // Update frustum culler\n this.frustumCuller.update();\n\n // Update raycaster with current node and edge objects\n this.raycasterManager.setNodeObjects(this.nodeManager.getAllNodeObjects());\n this.raycasterManager.setEdgeObjects(this.edgeManager.getAllEdgeLines());\n }\n\n // ==========================================================================\n // Public API\n // ==========================================================================\n\n /**\n * Sets the graph data\n */\n setData(data: GraphData): void {\n // Normalize data format: unwrap nested { data: { nodes, links } } if present\n const normalizedData: GraphData = (data as any).data?.nodes\n ? (data as any).data\n : data;\n\n // Accept both 'edges' and 'links' as the edge array\n const rawEdges = normalizedData.edges || normalizedData.links || [];\n\n // Normalize edges: map 'label' to 'relationship' if not already set\n const edges: Edge[] = rawEdges.map((e: Edge) => ({\n ...e,\n relationship: e.relationship || e.label || 'related_to',\n }));\n\n const graphData: GraphData = {\n nodes: normalizedData.nodes || [],\n edges,\n };\n\n // Store data for view switching\n this.graphData = graphData;\n\n // Clear existing data\n this.edgeManager.clear();\n this.nodeManager.clear();\n\n // Add nodes\n if (graphData.nodes && Array.isArray(graphData.nodes)) {\n // Set expected count so spawn positions scale with graph size\n NodeManager.setExpectedNodeCount(graphData.nodes.length);\n for (const nodeData of graphData.nodes) {\n this.addNode(nodeData);\n }\n }\n\n // Add edges\n if (graphData.edges && Array.isArray(graphData.edges)) {\n for (const edgeData of graphData.edges) {\n this.addEdge(edgeData);\n }\n }\n\n // Update graph engine references\n this.graphEngine = new GraphEngine(\n this.nodeManager.getAllNodes(),\n this.edgeManager.getAllEdges(),\n {\n repulsionStrength: this.options.repulsionStrength,\n attractionStrength: this.options.attractionStrength,\n damping: this.options.damping,\n useBarnesHut: this.options.useBarnesHut,\n barnesHutTheta: this.options.barnesHutTheta,\n }\n );\n\n // Restart simulation\n this.graphEngine.restart();\n\n // Sync to 2D view if active\n if (this.forceGraph2D) {\n this.forceGraph2D.setData(graphData as { nodes: NodeData[]; edges: Edge[] });\n }\n }\n\n /**\n * Adds a node to the graph\n * @returns true if added, false if node already exists or invalid\n */\n addNode(nodeData: NodeData): boolean {\n if (!validateNodeData(nodeData)) {\n return false;\n }\n\n const success = this.nodeManager.addNode(nodeData);\n\n if (success) {\n this.graphEngine.restart();\n\n // Also add to 2D view if it exists\n if (this.forceGraph2D) {\n this.forceGraph2D.addNode(nodeData);\n }\n\n if (this.options.onNodeAdd) {\n this.options.onNodeAdd(nodeData);\n }\n this.emit('nodeAdd', nodeData);\n }\n\n return success;\n }\n\n /**\n * Removes a node from the graph\n * @returns true if removed, false if not found\n */\n removeNode(nodeId: string): boolean {\n if (!validateNodeId(nodeId)) {\n return false;\n }\n\n // First remove all connected edges\n this.edgeManager.removeEdgesForNode(nodeId);\n\n // Then remove the node\n const success = this.nodeManager.removeNode(nodeId);\n\n if (success) {\n this.graphEngine.restart();\n\n if (this.options.onNodeRemove) {\n this.options.onNodeRemove(nodeId);\n }\n this.emit('nodeRemove', nodeId);\n\n // Hide panel if it's showing this node\n if (this.panelManager.getCurrentNodeId() === nodeId) {\n this.panelManager.hide();\n }\n }\n\n return success;\n }\n\n /**\n * Updates a node's properties\n */\n updateNode(nodeId: string, updates: Partial<NodeData>): boolean {\n return this.nodeManager.updateNode(nodeId, updates);\n }\n\n /**\n * Adds an edge to the graph\n * @returns true if added, false if edge already exists or nodes don't exist\n */\n addEdge(edge: Edge): boolean {\n if (!validateEdgeData(edge)) {\n return false;\n }\n\n const success = this.edgeManager.addEdge(edge);\n\n if (success) {\n // Update graph engine edges\n this.graphEngine.setEdges(this.edgeManager.getAllEdges());\n this.graphEngine.restart();\n\n // Also add to 2D view if it exists\n if (this.forceGraph2D) {\n this.forceGraph2D.addEdge(edge);\n }\n\n if (this.options.onEdgeAdd) {\n this.options.onEdgeAdd(edge);\n }\n this.emit('edgeAdd', edge);\n }\n\n return success;\n }\n\n /**\n * Removes an edge from the graph\n * @returns true if removed, false if not found\n */\n removeEdge(source: string, target: string): boolean {\n const success = this.edgeManager.removeEdge(source, target);\n\n if (success) {\n // Update graph engine edges\n this.graphEngine.setEdges(this.edgeManager.getAllEdges());\n\n if (this.options.onEdgeRemove) {\n this.options.onEdgeRemove({ source, target });\n }\n this.emit('edgeRemove', { source, target });\n }\n\n return success;\n }\n\n /**\n * Expands a node by fetching more data\n * @param nodeId - The ID of the node to expand\n * @param depth - The depth of expansion (1-3 levels, default 1)\n * @param fetchFn - Optional fetch function to override the default\n */\n async expandNode(nodeId: string, depth: number = 1, fetchFn?: (nodeId: string, depth: number) => Promise<GraphData>): Promise<boolean> {\n const expandCallback = fetchFn ?? this.options.onExpand;\n\n if (!expandCallback) {\n console.warn('[ForceGraph3D] No expand callback provided');\n return false;\n }\n\n try {\n const newData = await expandCallback(nodeId, depth);\n\n if (newData.nodes && Array.isArray(newData.nodes)) {\n for (const nodeData of newData.nodes) {\n this.addNode(nodeData);\n }\n }\n\n if (newData.edges && Array.isArray(newData.edges)) {\n for (const edgeData of newData.edges) {\n this.addEdge(edgeData);\n }\n }\n\n // Hide panel after expand\n this.panelManager.hide();\n\n this.emit('expand', nodeId, newData);\n return true;\n } catch (error) {\n console.error('[ForceGraph3D] Error expanding node:', error);\n return false;\n }\n }\n\n /**\n * Gets a node by ID\n */\n getNode(nodeId: string): NodeData | undefined {\n return this.nodeManager.getNode(nodeId);\n }\n\n /**\n * Gets neighbor nodes for a node\n */\n getNeighbors(nodeId: string): NodeData[] {\n const neighborIds = this.edgeManager.getNeighborIds(nodeId);\n return neighborIds\n .map(id => this.nodeManager.getNode(id))\n .filter((n): n is InternalNode => n !== undefined);\n }\n\n /**\n * Gets the number of nodes\n */\n getNodeCount(): number {\n return this.nodeManager.getNodeCount();\n }\n\n /**\n * Gets the number of edges\n */\n getEdgeCount(): number {\n return this.edgeManager.getEdgeCount();\n }\n\n /**\n * Sets the expand callback\n * @param callback - Function that fetches expansion data given a nodeId and depth\n */\n setExpandCallback(callback: (nodeId: string, depth?: number) => Promise<GraphData>): void {\n this.options.onExpand = callback;\n }\n\n /**\n * Focuses the camera on a specific node with smooth animation\n */\n focusOnNode(nodeId: string, distance: number = 30): void {\n // Handle 2D view\n if (this.viewMode === '2d' && this.forceGraph2D) {\n this.forceGraph2D.focusOnNode(nodeId);\n return;\n }\n\n const node = this.nodeManager.getNode(nodeId);\n if (!node) {\n console.warn(`[ForceGraph3D] Node \"${nodeId}\" not found`);\n return;\n }\n\n const targetPos = node.position;\n const camera = this.sceneManager.camera;\n const controls = this.sceneManager.controls;\n\n // Calculate target camera position (offset from node)\n const direction = camera.position.clone().sub(controls.target).normalize();\n const newCameraPos = {\n x: targetPos.x + direction.x * distance,\n y: targetPos.y + direction.y * distance,\n z: targetPos.z + direction.z * distance,\n };\n\n // Animate camera and controls target\n const startCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z };\n const startTarget = { x: controls.target.x, y: controls.target.y, z: controls.target.z };\n const duration = 800;\n const startTime = performance.now();\n\n const animate = () => {\n const elapsed = performance.now() - startTime;\n const progress = Math.min(elapsed / duration, 1);\n\n // Ease out cubic\n const eased = 1 - Math.pow(1 - progress, 3);\n\n // Interpolate camera position\n camera.position.x = startCameraPos.x + (newCameraPos.x - startCameraPos.x) * eased;\n camera.position.y = startCameraPos.y + (newCameraPos.y - startCameraPos.y) * eased;\n camera.position.z = startCameraPos.z + (newCameraPos.z - startCameraPos.z) * eased;\n\n // Interpolate controls target\n controls.target.x = startTarget.x + (targetPos.x - startTarget.x) * eased;\n controls.target.y = startTarget.y + (targetPos.y - startTarget.y) * eased;\n controls.target.z = startTarget.z + (targetPos.z - startTarget.z) * eased;\n\n controls.update();\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n }\n };\n\n animate();\n }\n\n /**\n * Focuses the camera on an edge (both source and target nodes) with smooth animation\n * Camera targets the midpoint and zooms out enough to see both nodes\n */\n focusOnEdge(sourceId: string, targetId: string, padding: number = 1.5): void {\n const sourceNode = this.nodeManager.getNode(sourceId);\n const targetNode = this.nodeManager.getNode(targetId);\n\n if (!sourceNode || !targetNode) {\n console.warn(`[ForceGraph3D] Could not find nodes for edge \"${sourceId}\" -> \"${targetId}\"`);\n return;\n }\n\n const camera = this.sceneManager.camera;\n const controls = this.sceneManager.controls;\n\n // Calculate midpoint between the two nodes\n const midpoint = {\n x: (sourceNode.position.x + targetNode.position.x) / 2,\n y: (sourceNode.position.y + targetNode.position.y) / 2,\n z: (sourceNode.position.z + targetNode.position.z) / 2,\n };\n\n // Calculate distance between nodes\n const dx = targetNode.position.x - sourceNode.position.x;\n const dy = targetNode.position.y - sourceNode.position.y;\n const dz = targetNode.position.z - sourceNode.position.z;\n const nodeDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n // Calculate camera distance (far enough to see both nodes with padding)\n // Use the node distance with padding factor, minimum of 40\n const cameraDistance = Math.max(nodeDistance * padding, 40);\n\n // Calculate target camera position (offset from midpoint in camera's current direction)\n const direction = camera.position.clone().sub(controls.target).normalize();\n const newCameraPos = {\n x: midpoint.x + direction.x * cameraDistance,\n y: midpoint.y + direction.y * cameraDistance,\n z: midpoint.z + direction.z * cameraDistance,\n };\n\n // Animate camera and controls target\n const startCameraPos = { x: camera.position.x, y: camera.position.y, z: camera.position.z };\n const startTarget = { x: controls.target.x, y: controls.target.y, z: controls.target.z };\n const duration = 800;\n const startTime = performance.now();\n\n const animate = () => {\n const elapsed = performance.now() - startTime;\n const progress = Math.min(elapsed / duration, 1);\n\n // Ease out cubic\n const eased = 1 - Math.pow(1 - progress, 3);\n\n // Interpolate camera position\n camera.position.x = startCameraPos.x + (newCameraPos.x - startCameraPos.x) * eased;\n camera.position.y = startCameraPos.y + (newCameraPos.y - startCameraPos.y) * eased;\n camera.position.z = startCameraPos.z + (newCameraPos.z - startCameraPos.z) * eased;\n\n // Interpolate controls target to midpoint\n controls.target.x = startTarget.x + (midpoint.x - startTarget.x) * eased;\n controls.target.y = startTarget.y + (midpoint.y - startTarget.y) * eased;\n controls.target.z = startTarget.z + (midpoint.z - startTarget.z) * eased;\n\n controls.update();\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n }\n };\n\n animate();\n }\n\n /**\n * Shows the info panel for a specific node\n */\n showNodePanel(nodeId: string): void {\n const node = this.nodeManager.getNode(nodeId);\n if (!node) {\n console.warn(`[ForceGraph3D] Node \"${nodeId}\" not found`);\n return;\n }\n\n const neighbors = this.getNeighbors(nodeId);\n this.panelManager.show(node, neighbors);\n }\n\n /**\n * Searches nodes by label or ID (case-insensitive)\n * @returns Array of matching nodes\n */\n searchNodes(query: string): NodeData[] {\n if (!query || query.trim() === '') {\n return [];\n }\n\n const lowerQuery = query.toLowerCase().trim();\n const nodesMap = this.nodeManager.getAllNodes();\n const results: NodeData[] = [];\n\n nodesMap.forEach((node) => {\n const labelMatch = node.label?.toLowerCase().includes(lowerQuery);\n const idMatch = node.id?.toLowerCase().includes(lowerQuery);\n const typeMatch = (node as any).type?.toLowerCase().includes(lowerQuery);\n if (labelMatch || idMatch || typeMatch) {\n results.push(node);\n }\n });\n\n return results;\n }\n\n /**\n * Searches edges by relationship (case-insensitive)\n * @returns Array of matching edges with source/target node info\n */\n searchEdges(query: string): Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> {\n if (!query || query.trim() === '') {\n return [];\n }\n\n const lowerQuery = query.toLowerCase().trim();\n const allEdges = this.edgeManager.getAllEdges();\n const results: Array<{ edge: Edge; sourceNode: NodeData; targetNode: NodeData }> = [];\n\n for (const edge of allEdges) {\n const relationshipMatch = (edge as any).relationship?.toLowerCase().includes(lowerQuery);\n if (relationshipMatch) {\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n if (sourceNode && targetNode) {\n results.push({ edge, sourceNode, targetNode });\n }\n }\n }\n\n return results;\n }\n\n /**\n * Gets all nodes as an array\n */\n getAllNodes(): NodeData[] {\n const nodesMap = this.nodeManager.getAllNodes();\n return Array.from(nodesMap.values());\n }\n\n /**\n * Gets all edges\n */\n getAllEdges(): Edge[] {\n return this.edgeManager.getAllEdges();\n }\n\n /**\n * Checks if the graph is initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * Gets the current view mode\n */\n getViewMode(): ViewMode {\n return this.viewMode;\n }\n\n /**\n * Switches between 2D and 3D view modes\n */\n switchView(mode: ViewMode): void {\n if (this.viewMode === mode) return;\n\n this.viewMode = mode;\n\n // Hide panels when switching views\n this.panelManager.hide();\n this.edgePanelManager.hide();\n this.edgeTooltipManager.hide();\n\n if (mode === '2d') {\n // Switch to 2D mode\n // Hide 3D renderer\n this.sceneManager.renderer.domElement.style.display = 'none';\n this.rendererManager.stop();\n\n // Create 2D renderer if not exists\n if (!this.forceGraph2D) {\n this.forceGraph2D = new ForceGraph2D(this.container, {\n backgroundColor: '#0a0a0a',\n nodeRadius: 24,\n onNodeClick: (nodeData: NodeData) => {\n this.onNodeClick(nodeData);\n },\n onNodeHover: (nodeData: NodeData | null) => {\n if (this.options.onNodeHover) {\n this.options.onNodeHover(nodeData);\n }\n },\n onEdgeHover: (edge: Edge | null, event?: MouseEvent) => {\n if (edge && event) {\n // Get source and target node data for tooltip\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n if (sourceNode && targetNode) {\n this.edgeTooltipManager.show(\n edge,\n sourceNode,\n targetNode,\n event.clientX,\n event.clientY\n );\n }\n } else {\n this.edgeTooltipManager.hide();\n }\n },\n onEdgeClick: (edge: Edge) => {\n // Show edge panel when clicking a relationship\n const sourceNode = this.nodeManager.getNode(edge.source);\n const targetNode = this.nodeManager.getNode(edge.target);\n if (sourceNode && targetNode) {\n this.edgePanelManager.show(edge, sourceNode, targetNode);\n }\n }\n });\n\n // Load current data\n if (this.graphData) {\n this.forceGraph2D.setData(this.graphData as { nodes: NodeData[]; edges: Edge[] });\n // Sync positions from 3D\n this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes());\n }\n } else {\n this.forceGraph2D.show();\n // Sync positions from 3D\n this.forceGraph2D.syncFrom3D(this.nodeManager.getAllNodes());\n }\n } else {\n // Switch to 3D mode\n // Hide 2D renderer\n if (this.forceGraph2D) {\n this.forceGraph2D.hide();\n }\n\n // Show 3D renderer\n this.sceneManager.renderer.domElement.style.display = 'block';\n this.rendererManager.start();\n }\n\n // Emit view change event\n this.emit('viewChange', mode);\n }\n\n /**\n * Registers an event listener\n */\n on(event: EventType, callback: EventCallback): void {\n if (!this.eventCallbacks.has(event)) {\n this.eventCallbacks.set(event, []);\n }\n this.eventCallbacks.get(event)!.push(callback);\n }\n\n /**\n * Emits an event\n */\n private emit(event: EventType, ...args: unknown[]): void {\n const callbacks = this.eventCallbacks.get(event);\n if (callbacks) {\n callbacks.forEach(cb => cb(...args));\n }\n }\n\n /**\n * Sets physics parameters for both 3D and 2D views\n */\n setPhysicsParams(params: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n }): void {\n // Update 3D physics\n this.graphEngine.setPhysicsParams(params);\n this.graphEngine.restart();\n\n // Update 2D physics if available\n if (this.forceGraph2D) {\n this.forceGraph2D.setPhysicsParams(params);\n }\n }\n\n /**\n * Creates dev mode controls (only in development)\n */\n private createDevControls(): void {\n this.devControls = document.createElement('div');\n this.devControls.className = 'force-graph-dev-controls';\n this.devControls.innerHTML = `\n <style>\n .force-graph-dev-controls {\n position: absolute;\n top: 20px;\n right: 20px;\n background: rgba(0, 0, 0, 0.8);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n padding: 16px;\n color: white;\n font-family: 'Inter', -apple-system, sans-serif;\n font-size: 12px;\n z-index: 1001;\n min-width: 220px;\n }\n .force-graph-dev-controls h3 {\n margin: 0 0 12px 0;\n font-size: 14px;\n color: #60a5fa;\n }\n .force-graph-dev-controls .control-group {\n margin-bottom: 12px;\n }\n .force-graph-dev-controls label {\n display: block;\n margin-bottom: 4px;\n color: rgba(255, 255, 255, 0.7);\n }\n .force-graph-dev-controls input[type=\"range\"] {\n width: 100%;\n margin-top: 4px;\n }\n .force-graph-dev-controls .value {\n color: #60a5fa;\n font-weight: 600;\n }\n .force-graph-dev-controls .stats {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n }\n </style>\n <h3>⚙️ Dev Controls</h3>\n <div class=\"control-group\">\n <label>Repulsion: <span class=\"value\" id=\"dev-repulsion-val\">${this.options.repulsionStrength}</span></label>\n <input type=\"range\" id=\"dev-repulsion\" min=\"10\" max=\"500\" value=\"${this.options.repulsionStrength}\">\n </div>\n <div class=\"control-group\">\n <label>Attraction: <span class=\"value\" id=\"dev-attraction-val\">${(this.options.attractionStrength ?? 0.01).toFixed(3)}</span></label>\n <input type=\"range\" id=\"dev-attraction\" min=\"1\" max=\"100\" value=\"${(this.options.attractionStrength ?? 0.01) * 1000}\">\n </div>\n <div class=\"control-group\">\n <label>Damping: <span class=\"value\" id=\"dev-damping-val\">${this.options.damping}</span></label>\n <input type=\"range\" id=\"dev-damping\" min=\"50\" max=\"99\" value=\"${(this.options.damping ?? 0.9) * 100}\">\n </div>\n <div class=\"stats\">\n <div>Nodes: <span class=\"value\" id=\"dev-node-count\">0</span></div>\n <div>Edges: <span class=\"value\" id=\"dev-edge-count\">0</span></div>\n <div>FPS: <span class=\"value\" id=\"dev-fps\">60</span></div>\n </div>\n `;\n\n this.container.appendChild(this.devControls);\n\n // Setup event listeners\n const repulsionSlider = this.devControls.querySelector('#dev-repulsion') as HTMLInputElement;\n const attractionSlider = this.devControls.querySelector('#dev-attraction') as HTMLInputElement;\n const dampingSlider = this.devControls.querySelector('#dev-damping') as HTMLInputElement;\n\n repulsionSlider?.addEventListener('input', () => {\n const value = parseFloat(repulsionSlider.value);\n this.setPhysicsParams({ repulsionStrength: value });\n (this.devControls!.querySelector('#dev-repulsion-val') as HTMLElement).textContent = value.toString();\n });\n\n attractionSlider?.addEventListener('input', () => {\n const value = parseFloat(attractionSlider.value) / 1000;\n this.setPhysicsParams({ attractionStrength: value });\n (this.devControls!.querySelector('#dev-attraction-val') as HTMLElement).textContent = value.toFixed(3);\n });\n\n dampingSlider?.addEventListener('input', () => {\n const value = parseFloat(dampingSlider.value) / 100;\n this.setPhysicsParams({ damping: value });\n (this.devControls!.querySelector('#dev-damping-val') as HTMLElement).textContent = value.toFixed(2);\n });\n\n // Update stats periodically\n setInterval(() => {\n const nodeCount = this.devControls!.querySelector('#dev-node-count');\n const edgeCount = this.devControls!.querySelector('#dev-edge-count');\n const fps = this.devControls!.querySelector('#dev-fps');\n\n if (nodeCount) nodeCount.textContent = this.getNodeCount().toString();\n if (edgeCount) edgeCount.textContent = this.getEdgeCount().toString();\n if (fps) fps.textContent = this.rendererManager.getFPS().toString();\n }, 500);\n }\n\n /**\n * Destroys the graph and releases all resources\n */\n destroy(): void {\n // Stop animation\n this.rendererManager.dispose();\n\n // Dispose interaction\n this.panelManager.dispose();\n this.raycasterManager.dispose();\n this.edgeTooltipManager.dispose();\n if (this.searchManager) {\n this.searchManager.dispose();\n }\n if (this.viewToggleManager) {\n this.viewToggleManager.dispose();\n }\n\n // Dispose 2D renderer\n if (this.forceGraph2D) {\n this.forceGraph2D.dispose();\n }\n\n // Dispose managers\n this.edgeManager.dispose();\n this.nodeManager.dispose();\n\n // Dispose factories\n this.nodeFactory.dispose();\n this.materialFactory.dispose();\n\n // Dispose scene\n this.sceneManager.dispose();\n\n // Remove dev controls\n if (this.devControls && this.devControls.parentNode) {\n this.devControls.parentNode.removeChild(this.devControls);\n }\n\n // Clear event callbacks\n this.eventCallbacks.clear();\n\n this.initialized = false;\n }\n}\n","import type { GraphData, NodeData, Edge } from '../utils/types';\n\n/**\n * Sample Data Generator\n * Generates sample graph data for testing and demos\n */\n\nconst NODE_LABELS = [\n 'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon',\n 'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa',\n 'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron',\n 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon',\n 'Phi', 'Chi', 'Psi', 'Omega', 'Core',\n 'Hub', 'Node', 'Link', 'Point', 'Vertex',\n];\n\nconst RELATIONSHIPS = [\n 'connects to',\n 'links with',\n 'relates to',\n 'depends on',\n 'references',\n 'extends',\n 'includes',\n 'partners with',\n 'collaborates with',\n 'supports',\n];\n\n// White and tangerine color palette\nconst NODE_COLORS = [\n 0xffffff, // White\n 0xff9966, // Tangerine\n 0xffcc99, // Light peach\n 0xffeedd, // Cream\n 0xff8844, // Darker tangerine\n];\n\n/**\n * Generates sample graph data with the specified number of nodes\n */\nexport function generateSampleData(nodeCount: number = 30): GraphData {\n const nodes: NodeData[] = [];\n const edges: Edge[] = [];\n\n // Create nodes with white/tangerine colors\n for (let i = 0; i < nodeCount; i++) {\n const label = i < NODE_LABELS.length\n ? NODE_LABELS[i]\n : `Node ${i + 1}`;\n\n nodes.push({\n id: `node-${i}`,\n label: label,\n color: NODE_COLORS[i % NODE_COLORS.length],\n position: {\n x: (Math.random() - 0.5) * 60,\n y: (Math.random() - 0.5) * 60,\n z: (Math.random() - 0.5) * 60,\n },\n });\n }\n\n // Create a connected graph\n // First, create a spanning tree to ensure connectivity\n for (let i = 1; i < nodeCount; i++) {\n const targetIndex = Math.floor(Math.random() * i);\n edges.push({\n source: `node-${i}`,\n target: `node-${targetIndex}`,\n relationship: RELATIONSHIPS[Math.floor(Math.random() * RELATIONSHIPS.length)],\n });\n }\n\n // Add some extra edges for more connectivity\n const extraEdges = Math.floor(nodeCount * 0.5);\n for (let i = 0; i < extraEdges; i++) {\n const sourceIndex = Math.floor(Math.random() * nodeCount);\n let targetIndex = Math.floor(Math.random() * nodeCount);\n\n // Avoid self-loops and ensure different nodes\n if (sourceIndex === targetIndex) {\n targetIndex = (targetIndex + 1) % nodeCount;\n }\n\n const source = `node-${sourceIndex}`;\n const target = `node-${targetIndex}`;\n\n // Check if edge already exists (will be handled by EdgeManager anyway)\n const edgeExists = edges.some(e =>\n (e.source === source && e.target === target) ||\n (e.source === target && e.target === source)\n );\n\n if (!edgeExists) {\n edges.push({\n source,\n target,\n relationship: RELATIONSHIPS[Math.floor(Math.random() * RELATIONSHIPS.length)],\n });\n }\n }\n\n return { nodes, edges };\n}\n\n/**\n * Generates a large sample dataset for performance testing\n */\nexport function generateLargeSampleData(nodeCount: number = 1000): GraphData {\n const nodes: NodeData[] = [];\n const edges: Edge[] = [];\n\n // Create nodes in clusters\n const clusterCount = Math.ceil(nodeCount / 50);\n const clusterCenters: Array<{ x: number; y: number; z: number }> = [];\n\n // Generate cluster centers\n for (let c = 0; c < clusterCount; c++) {\n clusterCenters.push({\n x: (Math.random() - 0.5) * 200,\n y: (Math.random() - 0.5) * 200,\n z: (Math.random() - 0.5) * 200,\n });\n }\n\n // Create nodes (no colors - clear glass)\n for (let i = 0; i < nodeCount; i++) {\n const cluster = clusterCenters[i % clusterCount];\n\n nodes.push({\n id: `node-${i}`,\n label: `N${i}`,\n position: {\n x: cluster.x + (Math.random() - 0.5) * 40,\n y: cluster.y + (Math.random() - 0.5) * 40,\n z: cluster.z + (Math.random() - 0.5) * 40,\n },\n });\n }\n\n // Create spanning tree for connectivity\n for (let i = 1; i < nodeCount; i++) {\n // Connect to a node in the same cluster or previous\n const clusterStart = Math.floor(i / 50) * 50;\n const targetIndex = clusterStart === 0\n ? Math.floor(Math.random() * i)\n : clusterStart + Math.floor(Math.random() * Math.min(i - clusterStart, 50));\n\n edges.push({\n source: `node-${i}`,\n target: `node-${Math.min(targetIndex, i - 1)}`,\n relationship: 'links to',\n });\n }\n\n // Connect clusters\n for (let c = 1; c < clusterCount; c++) {\n const sourceNode = c * 50;\n const targetNode = (c - 1) * 50 + Math.floor(Math.random() * 50);\n edges.push({\n source: `node-${sourceNode}`,\n target: `node-${targetNode}`,\n relationship: 'bridges to',\n });\n }\n\n return { nodes, edges };\n}\n"],"names":["DEFAULT_OPTIONS","LODLevel","createContainer","container","validateContainer","getContainerDimensions","rect","validateNodeData","node","n","isValidPosition","validateEdgeData","edge","validateNodeId","id","pos","p","createEdgeKey","source","target","_changeEvent","_startEvent","_endEvent","_ray","Ray","_plane","Plane","TILT_LIMIT","MathUtils","OrbitControls","EventDispatcher","object","domElement","Vector3","MOUSE","TOUCH","spherical","onKeyDown","scope","state","STATE","offset","quat","Quaternion","quatInverse","lastPosition","lastQuaternion","lastTargetPosition","twoPI","deltaTime","position","rotateLeft","getAutoRotationAngle","sphericalDelta","min","max","panOffset","performCursorZoom","clampDistance","scale","zoomChanged","newRadius","prevRadius","radiusDelta","dollyDirection","mouseBefore","mouse","mouseAfter","EPS","onContextMenu","onPointerDown","onPointerUp","onMouseWheel","onPointerMove","Spherical","rotateStart","Vector2","rotateEnd","rotateDelta","panStart","panEnd","panDelta","dollyStart","dollyEnd","dollyDelta","pointers","pointerPositions","controlActive","getZoomScale","delta","normalizedDelta","angle","rotateUp","panLeft","v","distance","objectMatrix","panUp","pan","deltaX","deltaY","element","targetDistance","dollyOut","dollyScale","dollyIn","updateZoomParameters","x","y","dx","dy","w","h","dist","handleMouseDownRotate","event","handleMouseDownDolly","handleMouseDownPan","handleMouseMoveRotate","handleMouseMoveDolly","handleMouseMovePan","handleMouseWheel","handleKeyDown","needsUpdate","handleTouchStartRotate","getSecondPointerPosition","handleTouchStartPan","handleTouchStartDolly","handleTouchStartDollyPan","handleTouchStartDollyRotate","handleTouchMoveRotate","handleTouchMovePan","handleTouchMoveDolly","centerX","centerY","handleTouchMoveDollyPan","handleTouchMoveDollyRotate","addPointer","onTouchStart","onMouseDown","onTouchMove","onMouseMove","removePointer","mouseAction","customWheelEvent","mode","newEvent","interceptControlDown","interceptControlUp","trackPointer","i","pointerId","SceneManager","options","__publicField","THREE","width","height","fov","camPos","ambientLight","keyLight","fillLight","rimLight","accentLight1","accentLight2","accentLight3","direction","child","_NodeManager","sceneManager","nodeFactory","nodeId","count","nodeData","lodLevel","spread","internalNode","nodeObject","updates","key","objects","spheres","_","NodeManager","EdgeManager","nodeManager","edgeFactory","edgeData","edgeKey","sourceNode","targetNode","edgeObject","index","e","edgesToRemove","neighbors","eo","GraphEngine","nodes","edges","nodeCount","nodesArray","effectiveRepulsion","nodeA","j","nodeB","dz","distSq","force","fx","fy","fz","octree","Octree","octreeNode","safeDist","attractionMultiplier","gravity","speed","params","bounds","padding","depth","size","totalMass","com","midX","midY","midZ","octants","idx","childBounds","children","RendererManager","onSimulate","onRender","targetFPS","currentTime","elapsed","fpsElapsed","fps","MaterialFactory","faces","faceConfigs","config","faceCanvas","faceCtx","gradient","imageData","noise","c","img","_color","cacheKey","threeColor","material","color","opacity","text","fontSize","canvas","ctx","textWidth","texture","NodeFactory","materialFactory","nodeRadius","lodSegments","defaultNodeColor","segments","group","geometry","sphere","labelMaterial","label","newLodLevel","newGeometry","EdgeFactory","edgeColor","edgeOpacity","sourcePos","targetPos","positions","line","posArray","LODManager","camera","lodDistances","enabled","LODLevelEnum","maxDistance","distances","FrustumCuller","point","radius","start","end","startPoint","endPoint","center","RaycasterManager","callback","edgeInfo","newHoveredNodeId","newHoveredEdgeKey","intersects","obj","_a","userData","screenX","screenY","PanelManager","value","template","styles","content","expandBtn","depthSelect","closeBtn","colorHex","div","EdgePanelManager","sourceBtn","targetBtn","sourceColorHex","targetColorHex","relationship","EdgeTooltipManager","mouseX","mouseY","tooltipRect","viewportWidth","viewportHeight","left","top","SearchManager","wrapper","style","query","nodeResults","edgeResults","html","typeLabel","item","ViewToggleManager","btn2D","btn3D","btn","DEFAULT_2D_OPTIONS","ForceGraph2D","dpr","zoomFactor","newScale","scaleChange","worldPos","wasClick","lengthSq","t","projX","projY","distX","distY","animate","minDistance","maxVelocity","totalEnergy","targetDist","gridSize","dotRadius","offsetX","offsetY","isHovered","isSelected","isConnectedToHoveredEdge","glowGradient","alpha","nodeGradient","r","g","b","maxWidth","data","targetX","targetY","startX","startY","duration","startTime","progress","eased","nodesMap","node3d","node2d","ForceGraph3D","info","normalizedData","graphData","success","fetchFn","expandCallback","newData","error","controls","newCameraPos","startCameraPos","startTarget","sourceId","targetId","midpoint","nodeDistance","cameraDistance","lowerQuery","results","labelMatch","idMatch","_b","typeMatch","_c","allEdges","args","callbacks","cb","repulsionSlider","attractionSlider","dampingSlider","edgeCount","NODE_LABELS","RELATIONSHIPS","NODE_COLORS","generateSampleData","targetIndex","extraEdges","sourceIndex","generateLargeSampleData","clusterCount","clusterCenters","cluster","clusterStart"],"mappings":"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","x_google_ignoreList":[3]}
|