To help visitors explore the relationships between topics, blog posts, and academic publications, this website features interactive network graph visualizations. Recently, we gave this visualization system a major architectural and aesthetic overhaul.
Instead of a monolithic script, the system now runs on a modular, multi-engine architecture supporting Cytoscape.js, D3.js, Sigma.js, Vis.js Network, and an immersive 3D Force Graph powered by Three.js and WebGL.
Here is a technical walkthrough of how we restructured the system, implemented layout algorithms with smooth animations, added live theme-awareness, and synchronized user settings via the URL.
1. How Does the Modular Multi-Engine Visualization Architecture Work?
The modular multi-engine visualization architecture decouples graph layout logic from the Astro presentation layer by encapsulating each rendering framework into standalone ES modules conforming to a unified lifecycle interface. Dynamic runtime imports load heavyweight WebGL or canvas dependencies strictly on demand, cutting initial bundle weights while preserving cross-engine theme and state synchronization.

Originally, the logic for loading libraries and initializing the graphs was crammed directly inside our Astro page. This made it difficult to maintain and expand. To resolve this, we extracted the code into a modular structure where each graphing engine is defined as a standalone JavaScript ES module.
Every engine conforms to a unified interface:
export default {
layouts: [
{ id: 'force', label: 'Force Directed (Organic)' },
{ id: 'radial', label: 'Concentric Rings' },
{ id: 'columns', label: 'Structured Columns' }
],
async init(container, payload, layout, isLight) { ... },
updateLayout(layout, isLight) { ... },
destroy() { ... }
}
The Astro template [slug].astro dynamically imports the selected engine at runtime using code splitting:
const engineModule = await import(`../../content/visualizations/${type}/engine.js`);
const engine = engineModule.default;
activeInstance = await engine.init(container, payload, currentLayout, isLight);
This drastically reduces the initial page bundle size, loading dependencies like Three.js or Vis.js only when the user selects that specific engine.
2. Which WebGL and Canvas Engines Power Interactive Graph Visualizations?
Alongside our existing Cytoscape, D3, and Sigma engines, we introduced two new visualization engines:
| Engine | Rendering Backend | Node Capacity | Primary Physics Model | Best Architectural Use Case |
|---|---|---|---|---|
| Sigma.js | WebGL 2.0 Shader Pipeline | 1,000–50,000+ | ForceAtlas2 (Web Worker) | Massive networks requiring high FPS throughput |
| Vis.js | HTML5 2D Canvas | 50–1,000 | Barnes-Hut Spring Damper | Tactile drag-and-drop & interactive exploration |
| 3D Force | WebGL & Three.js | 500–5,000 | 3D Force-Directed Sphere | Immersive volumetric spatial visualization |
| Cytoscape | HTML5 2D Canvas | 100–2,000 | Concentric / Compound Tree | Graph-theoretical & hierarchical analysis |
| D3.js | SVG Vector DOM | 50–500 | D3-Force Velocity Verlet | Vector typography & crisp publication graphics |
3D Force Graph (WebGL & Three.js)
The 3D Force Graph engine (3d-force/engine.js) renders the network as a floating three-dimensional sphere.

- Volumetric Rendering: Users can rotate, zoom, and pan around the network using an orbit controller.
- Dynamic Particles: To show connections actively, we enabled directional particles traveling along links.
- Three.js Context: Built on WebGL, it runs fluidly at 60 FPS even with complex force calculations.
Vis.js Network (HTML5 Canvas)
The Vis.js engine (vis-network/engine.js) provides an incredibly smooth 2D canvas visualization.

- Elastic Physics: Nodes react like spring-mass dampers, settling into place with organic bouncing effects.
- Custom Shapes & Labels: Each node type (Tag, Post, Publication) is color-coded and sized proportionally based on its degree of connections, with custom font configurations matching our typography.
- Interaction Events: Handles hover states and double-clicks cleanly to navigate users directly to posts or publications.
3. How Can Coordinate Transitions and Organic Layouts Be Smoothly Animated?
A major feature of this update is the ability to toggle between three distinct layouts:
- Force Directed: Nodes self-organize organically based on charge repulsion and edge attraction forces.
- Concentric Rings (Radial): Topic tags cluster in a dense inner ring, while posts and publications radiate out in an outer concentric ring.
- Structured Columns (Category): Organizes nodes into vertical columns—posts on the left, tags in the center, and publications on the right.
Easing Coordinate Interpolation
Rather than snapping nodes instantly to new layouts (which is disorienting), we disable the physics solvers during transition and manually interpolate coordinates using a cubic ease-in-out function:
This is implemented in Javascript using requestAnimationFrame:
animateTo(targets, duration = 600) {
const startTime = performance.now();
const startPositions = this.network.getPositions(); // Fetch current positions
const step = (time) => {
const elapsed = time - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing calculation
const ease = progress < 0.5
? 4 * progress * progress * progress
: 1 - Math.pow(-2 * progress + 2, 3) / 2;
const updates = [];
this.nodes.forEach(n => {
const start = startPositions[n.id] || { x: 0, y: 0 };
const target = targets[n.id];
if (target) {
updates.push({
id: n.id,
x: start.x + (target.x - start.x) * ease,
y: start.y + (target.y - start.y) * ease
});
}
});
this.visNodes.update(updates);
if (progress < 1) {
this.animationFrameId = requestAnimationFrame(step);
}
};
this.animationFrameId = requestAnimationFrame(step);
}
4. Theme-Aware Style Syncing
The website supports light and dark modes. Network graphs rendered on a canvas or WebGL context don’t automatically update when the HTML document’s class changes.
To bridge this gap, we set up a custom listener for theme changes:
window.addEventListener('theme-changed', () => {
const isLight = document.documentElement.classList.contains('light');
if (activeInstance) {
const params = new URLSearchParams(window.location.search);
const currentLayout = params.get('layout') || activeInstance.layouts[0].id;
activeInstance.updateLayout(currentLayout, isLight);
}
});
Within each engine, updateLayout updates the node and label colors, background properties, and edge styles on the fly:
- Cytoscape: Updates node label colors using the stylesheet selector APIs (
cy.style().selector('node').style(...)). - D3: Updates svg attributes (
nodeElements.selectAll("text").style("fill", ...)). - 3D Force: Readjusts the renderer background color and edge material properties dynamically.
- Vis.js: Modifies datasets in batches and calls
.update()to tell the canvas to repaint.
This guarantees that toggling between light and dark modes feels completely seamless, with no ugly canvas flashes or context losses.
5. URL State Synchronization
When users discover a layout they like (e.g., concentric rings in Vis.js), navigating away and returning shouldn’t reset their choice. We resolved this by persisting the layout ID directly into the browser’s URL query string.
When a layout is selected from the dropdown:
selector.addEventListener('change', (e) => {
const newLayout = e.target.value;
if (activeInstance) {
const url = new URL(window.location.href);
url.searchParams.set('layout', newLayout);
window.history.pushState({}, '', url.toString()); // Update URL without reloading
const isLight = document.documentElement.classList.contains('light');
activeInstance.updateLayout(newLayout, isLight);
}
});
On page load, the Astro script parses the URL parameters to fetch the state, initializing the canvas directly with the user’s preferred layout.
Conclusion & Live Interactive Demos
With this modular refactoring, the graph visualization page is more robust, lighter on initial loading speeds, and visually synchronized with the rest of the website. Whether you prefer the organic physics of Vis.js, the raw data transparency of D3, or the futuristic fly-throughs of the 3D Force Graph, the system delivers a premium, smooth interactive experience in light and dark mode alike.
Explore each engine live in action on the website:
- Sigma.js: ForceAtlas2 Network Graph – High-performance WebGL graph layout with web workers.
- Vis.js: Physics-Based Network Graph – Smooth physics-driven 2D particle network on HTML5 canvas.
- 3D Force: Volumetric Network Graph – Immersive spatial exploration built on Three.js & WebGL.
- Cytoscape.js: Semantic Network Graph – Versatile graph-theoretical layouts.
- D3.js: Force-Directed Network Graph – Physics-based force layout with delicate vector typography.
Browse the complete collection on the Content Visualizations Hub.