Overview
Three.js is the 3D graphics library used in the Prismatic Platform for creating immersive visualizations of complex data relationships. It leverages WebGL to render hardware-accelerated 3D scenes directly in the browser, enabling the platform to display network topologies, agent interaction graphs, and attack surface maps in an intuitive three-dimensional space that reveals structural patterns invisible in traditional 2D charts.
The Prismatic Platform uses Three.js for its hero animations on the promotional site, 3D network topology views in the Perimeter EASM dashboard, and interactive agent constellation visualizations where each of the platform's 404 agents is represented as a node in a force-directed 3D graph. These 3D representations help users understand complex relationships between agents, data sources, and security entities that would be difficult to convey in traditional 2D charts or tables. A security analyst can rotate the attack surface graph to discover clusters of related assets, zoom into specific threat vectors, and click on individual nodes for detailed intelligence.
Three.js's scene graph architecture and extensive geometry, material, and lighting systems provide the flexibility needed to create both decorative visual elements (the animated particle background on the landing page) and functional data exploration interfaces (the rotatable, zoomable intelligence graph). The library integrates with Phoenix LiveView through JavaScript hooks that manage the scene lifecycle and receive data updates from the server without full page reloads.
Key Features
- WebGL Rendering: Hardware-accelerated 3D graphics in the browser with automatic fallback detection for unsupported devices
- Scene Graph: Hierarchical object management with cameras, lights, nested groups, and automatic matrix transformations
- Geometries: Built-in shapes (sphere, box, torus, plane) and custom
BufferGeometryfor efficient vertex-level data visualization - Materials: PBR (physically based rendering) materials, custom GLSL shaders, and post-processing effects for polished visuals
- Animation: Keyframe animation system with mixer/clip architecture for smooth transitions and time-based interpolation
- Controls:
OrbitControlsfor interactive camera rotation, zoom, and pan with damping for natural movement feel - Instanced Rendering:
InstancedMeshfor rendering thousands of identical objects (agent nodes) with per-instance color and position without per-object draw calls - Raycasting: GPU-accelerated object picking enabling users to click on 3D objects for detail views and context menus
Platform Integration
Three.js powers the platform's 3D visualizations. Agent constellation views use force-directed layout to position nodes and render connecting edges with domain-based coloring.
// Agent constellation visualization with force-directed layout
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0a0f);
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({: true,: true });
renderer.setPixelRatio(window.devicePixelRatio);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Domain color mapping matching Tailwind color palette
const domainColors = {
: 0x3b82f6, // blue-500
: 0x8b5cf6, // violet-500
: 0x22c55e, // green-500
: 0xeab308, // yellow-500
: 0xef4444 // red-500
};
// Create agent nodes using instanced mesh for performance
const nodeGeometry = new THREE.SphereGeometry(0.3, 16, 16);
const instancedMesh = new THREE.InstancedMesh(
nodeGeometry,
new THREE.MeshPhongMaterial({: 80 }),
agents.length
);
const matrix = new THREE.Matrix4();
const color = new THREE.Color();
agents.forEach((agent, i) => {
matrix.setPositionagent.x, agent.y, agent.z;
instancedMesh.setMatrixAti, matrix;
color.setHexdomainColorsagent.domain || 0x6b7280;
instancedMesh.setColorAti, color;
});
scene.add(instancedMesh);
// Render connection edges between related agents
const edgeMaterial = new THREE.LineBasicMaterial({
: 0x374151,: true,: 0.3
});
connections.forEach(([from, to]) => {
const geometry = new THREE.BufferGeometry.setFromPoints
new THREE.Vector3from.x, from.y, from.z,
new THREE.Vector3to.x, to.y, to.z
;
scene.addnew THREE.Linegeometry, edgeMaterial;
});
The promotional site uses a particle animation on the landing page that responds to mouse movement, creating an atmospheric background effect:
// Particle background animation for the promotional site
function createParticleField(count) {
const geometry = new THREE.BufferGeometry;
const positions = new Float32Arraycount * 3;
const velocities = new Float32Arraycount * 3;
forlet i = 0; i < count * 3; i += 3 {
positionsi =Math.random - 0.5 * 100;
positionsi + 1 =Math.random - 0.5 * 100;
positionsi + 2 =Math.random - 0.5 * 50;
velocitiesi =Math.random - 0.5 * 0.02;
velocitiesi + 1 =Math.random - 0.5 * 0.02;
velocitiesi + 2 = 0;
}
geometry.setAttribute'position', new THREE.BufferAttributepositions, 3;
const material = new THREE.PointsMaterial{
: 0.15,: 0x14b8a6,: true,: 0.6
};
return {: new THREE.Pointsgeometry, material, velocities };
}Architecture
Three.js integrates with the platform's LiveView architecture through a hook-based lifecycle that ensures proper resource management.
| Component | Role | Platform Usage |
|---|---|---|
| Scene | Root container for all 3D objects | One scene per visualization widget |
| Camera | Viewport into the 3D world | PerspectiveCamera for interactive views |
| Renderer | WebGL context manager | One renderer per canvas element |
| Controls | User interaction handling | OrbitControls for rotation/zoom |
| InstancedMesh | Efficient multi-object rendering | Agent nodes (404+ instances) |
| BufferGeometry | Vertex data for custom shapes | Connection edges between agents |
| Raycaster | Object selection by mouse position | Click-to-select agent details |
| Animation Loop | requestAnimationFrame render cycle | 60fps continuous rendering |
For Phoenix LiveView integration, Three.js scenes are managed through hooks that handle initialization, data updates, and cleanup:
Hooks.AgentConstellation = {
mounted() {
this.initScene;
this.handleEvent"agents_updated", ({agents}) => {
this.updateNodesagents;
};
this.handleEvent"connection_added", ({from, to}) => {
this.addEdgefrom, to;
};
},
updated() {
// Handle DOM changes that might affect canvas size
this.resizeRenderer;
},
destroyed() {
// Dispose all GPU resources to prevent WebGL memory leaks
this.renderer.dispose;
this.scene.traverse(obj) => {
ifobj.geometry obj.geometry.dispose;
ifobj.material obj.material.dispose;
};
cancelAnimationFramethis.animationId;
}
};Performance Characteristics
Three.js rendering performance depends on the complexity of the scene and the capabilities of the client's GPU.
| Metric | Value | Context |
|---|---|---|
| Target framerate | 60 FPS | Interactive visualizations |
| Agent nodes (instanced) | 404+ at 60 FPS | InstancedMesh with 16-segment spheres |
| Connection edges | 1,000+ at 60 FPS | LineBasicMaterial with transparency |
| Draw calls (constellation) | 2-5 | Instanced rendering minimizes draw calls |
| GPU memory | ~50MB | Full constellation with particle background |
| JS bundle size | ~600KB | Three.js + OrbitControls (minified) |
| Scene initialization | <500ms | Including geometry creation and material setup |
| Raycaster per frame | <1ms | Object picking on hover/click |
Configuration
<!-- Three.js loaded via CDN with OrbitControls -->
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/examples/js/controls/OrbitControls.js">
</script>
Canvas configuration for LiveView integration:
<!-- LiveView template with Three.js canvas -->
<div id="constellation-container" phx-hook="AgentConstellation"
class="w-full h-[600px] rounded-xl overflow-hidden bg-gray-950">
<canvas id="constellation-canvas"></canvas>
</div>
Renderer initialization with optimal settings:
const renderer = new THREE.WebGLRenderer({
: document.getElementById('constellation-canvas'),
: true,
: true,
: 'high-performance'
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // Cap at 2x for performance
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;Best Practices
- Use
InstancedMeshfor many similar objects -- rendering 404 agent nodes individually would be far too slow; instanced rendering batches them into a single draw call - Dispose resources in
destroyedhooks -- Three.js geometries, materials, and textures must be explicitly disposed to prevent WebGL memory leaks - Enable damping on OrbitControls -- damped controls feel more natural and prevent disorienting sudden camera jumps during user interaction
- Detect WebGL support -- fall back to a 2D Chart.js visualization on devices without WebGL or with insufficient GPU capabilities
- Keep polygon counts low -- use
SphereGeometry(0.3, 16, 16)not(0.3, 64, 64)for data nodes that do not need high geometric detail - Cap pixel ratio at 2x --
Math.min(window.devicePixelRatio, 2)prevents excessive rendering on 3x+ displays, maintaining performance - Traverse and dispose on cleanup -- walk the scene graph to dispose every geometry, material, and texture when the component unmounts
Comparison with Alternatives
| Feature | Three.js | D3.js | Plotly | Babylon.js | deck.gl |
|---|---|---|---|---|---|
| Rendering | WebGL 3D | SVG/Canvas 2D | Canvas/WebGL | WebGL 3D | WebGL 2D/3D |
| Use case | 3D visualization, animation | Data visualization, charts | Scientific plots | Games, 3D apps | Geospatial/large datasets |
| Learning curve | Medium | High | Low | High | Medium |
| Performance (1000+ objects) | Excellent (instancing) | Poor (SVG DOM) | Good | Excellent | Excellent |
| Bundle size | ~600KB | ~250KB | ~3.5MB | ~1.2MB | ~400KB |
| LiveView integration | JS Hooks | JS Hooks | JS Hooks | JS Hooks | JS Hooks |
| Platform usage | 3D constellation, particles | Not used | Not used | Not used | Not used |
Three.js was chosen for the platform's 3D visualizations because it provides the best balance of rendering performance, API simplicity, and ecosystem maturity for WebGL-based interactive scenes.
Related Technologies
- Chart.js - 2D chart visualizations and fallback for non-WebGL devices
- Alpine.js - UI interaction handling alongside 3D scenes for menus and overlays
- KuzuDB - Graph data source for entity relationship visualization
- Phoenix LiveView - Server-side data delivery via hooks for real-time 3D updates
- TailwindCSS - Styling for the canvas container and overlay elements
Related Apps
- prismatic_web - 3D visualizations on LiveView dashboards including the agent constellation
- prismatic_perimeter - Attack surface topology visualization with 3D network graphs
- prismatic_agents - Agent data source for the constellation visualization
Connect & Contribute
Created by Tomáš Korcak (korczis) | Open Source under GHL