Back to blog
Three.jsWebGL

Building a 3D Tech Stack Visualisation with Three.js

03 Feb 20268 min read

Building a 3D Tech Stack Visualisation with Three.js

Introduction

Skill badges and icon grids are fine for a README, but for a portfolio website, you can do a lot better. When I was building my personal site at shavrka.studio, I wanted a tech stack section that actually felt alive — something that stopped visitors mid-scroll rather than blending into the background.

Three.js was the obvious tool for the job. It's a mature WebGL library with a massive ecosystem, excellent documentation, and enough abstraction that you're not writing raw shader code on day one. The result was an interactive 3D sphere of floating tech logos that users can rotate, hover, and interact with.

In this post I'll walk through how I built it — from scene setup to animation to React integration. It's less complex than it might sound, and the concepts transfer to dozens of other use cases.


Core Concepts

How Three.js Thinks

  • Scene — the container for all 3D objects
  • Camera — your viewpoint into the scene (typically PerspectiveCamera)
  • Renderer — the engine that draws the scene to a <canvas> using WebGL
  • Mesh — an object made of geometry (shape) + material (appearance)
  • Light — ambient or directional lighting that affects how materials look

The rendering loop looks like this:

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

That's the heartbeat of every Three.js project. Everything else is building objects, positioning them, and updating them on each frame.

Spherical Distribution of Points

To distribute objects evenly across a sphere's surface, I used the Fibonacci sphere algorithm — a technique that avoids clustering at the poles (which you get from naïve latitude/longitude loops):

function fibonacciSphere(n, radius) {
  const points = [];
  const goldenAngle = Math.PI * (3 - Math.sqrt(5)); // ~2.399 radians

  for (let i = 0; i < n; i++) {
    const y = 1 - (i / (n - 1)) * 2; // y from 1 to -1
    const r = Math.sqrt(1 - y * y);
    const theta = goldenAngle * i;

    points.push(
      new THREE.Vector3(
        Math.cos(theta) * r * radius,
        y * radius,
        Math.sin(theta) * r * radius
      )
    );
  }

  return points;
}

This gives you perfectly even distribution — no dead zones, no bunching. Pass in the number of icons you have and the sphere radius, and you get exactly that many positions.


Practical Examples

Scene Setup

import * as THREE from 'three';

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(
  75,                                          // field of view
  container.clientWidth / container.clientHeight, // aspect ratio
  0.1,                                         // near clipping plane
If this helped you, leave a ❤️

Comments

Coming Soon

Comment section will be available shortly

Have thoughts on this? Reach out — I'd love to chat.

Get in Touch