Lukachyna

Building a 3D Portfolio with Three.js: Lessons from the Deep End

Three.jsWebGLPortfolio

Building the 3D character on this portfolio was the most technically challenging thing I've done in a frontend context. Here's what I wish I'd known before starting — the GLTF pipeline, WebGL performance, and how to make Three.js play nicely with Angular SSR.

The GLTF Pipeline

GLTF is the right format for web 3D — compact, fast-loading, with excellent Three.js support. But getting from Blender to a web-ready asset took longer than expected. The key steps: optimize geometry, bake textures, export with Draco compression, and validate with the glTF Viewer before integrating.

The SSR Problem

Three.js depends on WebGL, which depends on a canvas element, which doesn't exist in Node.js. This means the LivingPortraitComponent had to be carefully isolated from the SSR render path. The solution: check isPlatformBrowser before initializing Three.js, and set a minimum height on the container to prevent layout shift.

typescript
// Core pattern for Three.js + Angular SSR
ngAfterViewInit(): void {
  if (!isPlatformBrowser(this.platformId)) return;

  // Safe to use WebGL here
  this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  this.initScene();
  this.animate();
}

Performance: What Actually Matters

The main performance levers for a Three.js portfolio scene: polygon count, texture resolution, draw calls, and animation complexity. The cartoon character was exported at ~18k polygons, uses a single 1024×1024 texture atlas, and runs at 60fps on mid-range mobile hardware.

Don't animate in a requestAnimationFrame loop if nothing is changing. Use a dirty flag to skip renders when the scene hasn't updated.

What I'd Do Differently

I'd start with a simpler model. The urge to use a highly-detailed character drove weeks of optimization work that a simpler low-poly model would have avoided entirely. For a portfolio piece, visual distinctiveness matters more than technical complexity.

Stepan Lukachyna

Frontend engineer, educator, and occasional researcher. Writes about web performance, architecture patterns, and the gaps in documentation no one tells you about.

Get in touch