3D force-directed graph with floating labels — plug data, get insight.
vort3x is a TypeScript-native wrapper around 3d-force-graph built for mind maps, OSINT graphs, and relationship visualizations.
Every node renders a floating label in 3D space — no hover required. Data flows in as a typed { nodes, links } object and comes out as an interactive vortex of connections.
npm install @roxdavirox/vort3xPeer dependency:
three >= 0.150.0
import { createVort3x } from '@roxdavirox/vort3x'
const graph = createVort3x('#graph', {
nodes: [
{ id: 'a', label: 'Node A', type: 'entity', subject: 'group1', risk: 'high' },
{ id: 'b', label: 'Node B', type: 'email', subject: 'group1', risk: 'mid' },
{ id: 'c', label: 'Node C', type: 'ip', subject: 'group2', risk: 'low' },
],
links: [
{ source: 'a', target: 'b' },
{ source: 'a', target: 'c', color: '#ff444455' },
],
})| Param | Type | Description |
|---|---|---|
element |
string | HTMLElement |
CSS selector or DOM element |
data |
Vort3xData |
{ nodes, links } |
options |
Vort3xOptions |
Theme, callbacks, particles |
Returns a Vort3xInstance.
interface Vort3xNode {
id: string // unique identifier
label: string // floating label text
type: string // drives node color (see theme)
layer?: 'net' | 'identity' | 'code' | 'shared'
subject?: string // group/owner — used for filtering
size?: number // sphere radius multiplier (default 6)
risk?: 'high' | 'mid' | 'low' | 'info' // sub-label color
desc?: string // description for click handlers
}interface Vort3xLink {
source: string // node id
target: string // node id
color?: string // hex with alpha e.g. '#ff444455'
}interface Vort3xOptions {
theme?: Partial<Vort3xTheme>
onNodeClick?: (node: Vort3xNode) => void
particles?: boolean // link directional particles (default true)
}// Filter by predicate — hides non-matching nodes and their links
graph.filter(node => node.subject === 'group1')
// Reset to full graph
graph.resetFilter()
// Fly camera to a node
graph.focusNode('a')
// Remove the graph from the DOM
graph.destroy()The default theme maps node.type to colors:
import { defaultTheme } from '@roxdavirox/vort3x'
const graph = createVort3x('#graph', data, {
theme: {
...defaultTheme,
nodeColors: {
...defaultTheme.nodeColors,
entity: '#aa44ff',
custom: '#00ccff',
},
},
})Default node types and colors:
| Type | Color |
|---|---|
layer |
#00ff88 |
ip |
#ff4444 |
dns |
#ff7744 |
asn |
#ff6655 |
geo |
#44ffaa |
infra |
#ff8800 |
vuln |
#ff3333 |
github |
#4488ff |
email |
#66aaff |
entity |
#aa44ff |
secret |
#ffaa00 |
deploy |
#ffcc44 |
import { createVort3x } from '@roxdavirox/vort3x'
const graph = createVort3x('#graph', data, {
onNodeClick: node => {
document.getElementById('detail-title').textContent = node.label
document.getElementById('detail-desc').textContent = node.desc ?? ''
},
})
// Filter by layer
document.getElementById('btn-net').addEventListener('click', () => {
graph.filter(n => n.layer === 'net' || n.type === 'layer')
})
// Filter by risk
document.getElementById('btn-risk').addEventListener('click', () => {
graph.filter(n => n.risk === 'high' || n.risk === 'mid')
})
// Reset
document.getElementById('btn-all').addEventListener('click', () => {
graph.resetFilter()
})const graph = createVort3x('#mindmap', {
nodes: [
{ id: 'root', label: 'Project', type: 'layer', size: 14 },
{ id: 'fe', label: 'Frontend', type: 'entity', subject: 'tech' },
{ id: 'be', label: 'Backend', type: 'entity', subject: 'tech' },
{ id: 'react', label: 'React', type: 'deploy', subject: 'tech' },
{ id: 'nest', label: 'NestJS', type: 'deploy', subject: 'tech' },
],
links: [
{ source: 'root', target: 'fe' },
{ source: 'root', target: 'be' },
{ source: 'fe', target: 'react' },
{ source: 'be', target: 'nest' },
],
}, { particles: false })- Labels first. Every node shows its label floating in 3D space — no hover, no click required to read the graph.
- Typed data in, typed instance out. No config objects with unknown shapes.
- fp-core inside. Internal data transformations use
@roxdavirox/fp-core—pipeandfilterfor link resolution and node filtering. - Thin wrapper. vort3x does not re-implement physics. It configures and extends 3d-force-graph with sane defaults for information graphs.
- Theme-driven colors. Node type drives color — consistent visual language across any dataset.
- TypeScript ≥ 5.0
three≥ 0.150.0 (peer dependency)"moduleResolution": "bundler"or"node16"
MIT © roxdavirox