🚀 Pipes 3D Blog
_ □ X
Creating 3D Pipes in the Browser with Three.js

Recreating the classic Windows 3D Pipes screensaver in modern browsers is easier than you might think, thanks to Three.js and modern WebGL capabilities.

Why Recreate a 30-Year-Old Screensaver?

The 3D Pipes screensaver, which debuted with Windows NT in 1992 and became iconic in Windows 95/98, represents a perfect intersection of nostalgia and technical challenge. It's complex enough to be interesting, but simple enough to understand. Plus, who didn't spend hours watching those colorful pipes wind their way across the screen?

Bringing this classic to the web browser demonstrates how far web technologies have come. What once required native Windows APIs and DirectX can now run smoothly in any modern browser, on any platform, without plugins.

The Building Blocks: Three.js Fundamentals

Three.js is a JavaScript library that makes WebGL accessible to mere mortals. Instead of wrestling with shader programs and vertex buffers, you can create 3D scenes with intuitive JavaScript code.

At its core, every Three.js application needs three essential components:

  • Scene: The 3D space where objects live
  • Camera: Your viewpoint into the scene
  • Renderer: The engine that draws everything to the screen

Setting Up Your Scene

import * as THREE from 'three';

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);

const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

Creating the Pipes: Procedural Generation

The magic of the 3D Pipes screensaver lies in its procedural generation. Each pipe segment must decide: go straight, turn left, turn right, go up, or go down. The trick is making these choices feel random while avoiding self-intersection.

Pipe Geometry

Pipes are essentially cylinders with joints (elbows and tees). Three.js makes creating these primitives straightforward:

// Create a straight pipe segment
const pipeGeometry = new THREE.CylinderGeometry(
    0.2,  // radius top
    0.2,  // radius bottom
    1.0,  // height
    12,   // radial segments
    1     // height segments
);

// Create an elbow joint (90-degree bend)
const elbowGeometry = new THREE.TorusGeometry(
    0.2,  // radius
    0.08, // tube diameter
    16,   // radial segments
    100,  // tubular segments
    Math.PI / 2  // arc (90 degrees)
);

Materials and Colors

The original screensaver used bold, saturated colors. Three.js's MeshPhongMaterial gives us nice shiny surfaces that catch the light:

const colors = [
    0xff0000, // Red
    0x00ff00, // Green
    0x0000ff, // Blue
    0xffff00, // Yellow
    0xff00ff, // Magenta
    0x00ffff  // Cyan
];

const material = new THREE.MeshPhongMaterial({
    color: colors[Math.floor(Math.random() * colors.length)],
    shininess: 100,
    specular: 0x444444
});

The Algorithm: Growing the Pipes

Each pipe grows one segment at a time. The algorithm needs to track the current position, direction, and ensure pipes don't grow outside the visible area or intersect themselves.

class PipeGrower {
    constructor(scene) {
        this.position = new THREE.Vector3(0, 0, 0);
        this.direction = new THREE.Vector3(1, 0, 0);
        this.color = this.randomColor();
        this.scene = scene;
    }

    grow() {
        // Add a straight segment in current direction
        this.addSegment();

        // Randomly decide to turn
        if (Math.random() < 0.3) {
            this.turn();
        }

        // Move forward
        this.position.add(this.direction.clone().multiplyScalar(1.0));

        // Check boundaries
        if (this.isOutOfBounds()) {
            this.reset();
        }
    }

    turn() {
        const turns = this.getPossibleTurns();
        const newDirection = turns[Math.floor(Math.random() * turns.length)];
        this.addElbow(this.direction, newDirection);
        this.direction = newDirection;
    }
}

Adding the Details: Lighting and Animation

Good lighting makes the difference between "meh" and "wow". The original screensaver had that characteristic glossy look that we can replicate:

// Ambient light for overall brightness
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);

// Directional light for highlights
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(10, 10, 10);
scene.add(directionalLight);

// Point light that follows the camera
const pointLight = new THREE.PointLight(0xffffff, 0.5);
camera.add(pointLight);
scene.add(camera);

Camera Movement

To recreate that dreamy, floating feeling of the original, we slowly rotate the camera around the scene:

function animate(time) {
    requestAnimationFrame(animate);

    // Slowly rotate camera
    camera.position.x = Math.cos(time * 0.0001) * 5;
    camera.position.y = Math.sin(time * 0.0002) * 3;
    camera.lookAt(scene.position);

    // Grow pipes
    pipes.forEach(pipe => pipe.grow());

    renderer.render(scene, camera);
}
animate(0);

Performance Optimization

As pipes grow, you'll accumulate thousands of segments. Without optimization, your framerate will tank. Here are key strategies:

  • Geometry Merging: Combine multiple pipe segments into single meshes to reduce draw calls
  • Frustum Culling: Let Three.js automatically skip rendering objects outside the camera view
  • Level of Detail: Use simpler geometry for distant pipes
  • Segment Limits: Remove old segments when pipes grow too long
// Limit total segments
if (this.segments.length > 100) {
    const oldSegment = this.segments.shift();
    this.scene.remove(oldSegment);
    oldSegment.geometry.dispose();
    oldSegment.material.dispose();
}

Adding Polish: The Finishing Touches

Small details make a big difference:

  • Joint Caps: Add spheres at pipe ends for a cleaner look
  • Varied Speeds: Make different pipes grow at different rates
  • Teapots: Yes, the original could place 3D teapots as joint connectors. Load an OBJ model for authentic nostalgia
  • Mixed Joint Types: Alternate between elbows, tees, and spheres

Beyond the Basics: Modern Enhancements

Since we're using modern web technologies, why not add some features the original never had?

  • Post-Processing: Add bloom effects for extra glow
  • Real-time Controls: Let users adjust speed, colors, and pipe count
  • Sound: Add subtle ambient audio that reacts to pipe generation
  • Mobile Support: Touch controls for rotation and zoom
  • VR Mode: Experience the pipes in virtual reality with WebXR

The Complete Pipeline

Here's the basic structure to get you started:

  1. Set up Three.js scene, camera, and renderer
  2. Create geometry templates for pipes and joints
  3. Implement the pipe growth algorithm
  4. Add lighting for that classic glossy look
  5. Implement camera rotation/movement
  6. Add performance optimizations
  7. Polish with details and effects

Lessons Learned

Recreating retro graphics teaches important lessons about procedural generation, 3D mathematics, and performance optimization. The constraints of the original (limited colors, simple geometry) actually make it more interesting to recreate - sometimes limitations breed creativity.

More importantly, projects like this bridge the past and present. They show that "old" doesn't mean "obsolete" - classic algorithms and designs still have value, both educational and aesthetic.

"The best part about recreating classic screensavers isn't the code - it's the moment when someone sees it and says 'Oh my god, I remember this!' That connection to the past, that shared cultural memory, that's what makes retro computing projects worthwhile."

Try It Yourself

The complete source code for this 3D Pipes implementation is available on our homepage. Open your browser's developer console while watching the pipes - you might spot some hidden features and Easter eggs we've included as a tribute to the original.

Whether you're a nostalgic Windows 95 veteran or a young developer curious about retro computing, rebuilding classics like this is both fun and educational. So fire up your code editor, import Three.js, and let's get those pipes flowing!

*** CLICK HERE *** EXPERIENCE THE MAGIC *** 3D PIPES SCREENSAVER ***