force-3d-graph 1.0.0
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/README.md +114 -0
- package/dist/force-3d-graph.js +2625 -0
- package/dist/force-3d-graph.js.map +1 -0
- package/dist/force-3d-graph.umd.cjs +336 -0
- package/dist/force-3d-graph.umd.cjs.map +1 -0
- package/dist/index.d.ts +320 -0
- package/package.json +55 -0
|
@@ -0,0 +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/EdgeTooltipManager.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 // 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: 100,\n attractionStrength: 0.01,\n damping: 0.9,\n useBarnesHut: false, // Auto-enabled for large graphs\n barnesHutTheta: 0.5,\n\n defaultNodeColor: 0x4A90E2,\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\n targetFPS: 60,\n maxVisibleNodes: 10000,\n};\n\n// ============================================================================\n// Event Types\n// ============================================================================\n\nexport type EventType =\n | 'nodeClick'\n | 'nodeHover'\n | 'edgeHover'\n | 'nodeAdd'\n | 'nodeRemove'\n | 'edgeAdd'\n | 'edgeRemove'\n | 'expand'\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\n constructor(\n materialFactory: MaterialFactory,\n nodeRadius: number = 2,\n lodSegments: number[] = [32, 16, 8]\n ) {\n this.materialFactory = materialFactory;\n this.nodeRadius = nodeRadius;\n this.lodSegments = lodSegments;\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 ?? 0x4A90E2\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\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: 0.5 }; // Increase line detection threshold\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 * Handles click events\n */\n private handleClick(event: MouseEvent): void {\n const nodeData = this.getIntersectedNode(event);\n\n if (nodeData && this.onNodeClick) {\n this.onNodeClick(nodeData);\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 }\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 }\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 ${this.escapeHtml(nodeData.label)}\n </h2>\n \n <div class=\"info-row\">\n <span class=\"info-label\">ID</span>\n <span class=\"info-value\">${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 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 {\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 { EdgeTooltipManager } from './interaction/EdgeTooltipManager';\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 edgeTooltipManager: EdgeTooltipManager;\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\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 );\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.edgeTooltipManager = new EdgeTooltipManager();\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\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 // 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 * 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 // 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\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 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 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 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 * 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 * 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\n */\n setPhysicsParams(params: {\n repulsionStrength?: number;\n attractionStrength?: number;\n damping?: number;\n }): void {\n this.graphEngine.setPhysicsParams(params);\n this.graphEngine.restart();\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\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","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","newHoveredNodeId","edgeInfo","newHoveredEdgeKey","intersects","obj","_a","userData","screenX","screenY","PanelManager","value","template","styles","content","expandBtn","depthSelect","closeBtn","colorHex","div","EdgeTooltipManager","mouseX","mouseY","tooltipRect","viewportWidth","viewportHeight","left","top","relationship","ForceGraph3D","info","data","success","fetchFn","expandCallback","newData","error","controls","newCameraPos","startCameraPos","startTarget","duration","startTime","animate","progress","eased","query","lowerQuery","nodesMap","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]}
|