DEV Community

Vampire.js
Vampire.js

Posted on

Building a 3D Exploration Game with Three.js

Banner

Back story (For performance optimizations, skip to the next section ;))

The game development club I am a part of had to present themselves in front of the freshers at my college, and being a Technical Head at the club, I thought it would be cool if we did something that sets us apart from the other clubs in the first impression itself.
Hence, we decided to make a game, and let the crowd play it during the presentation.

So, the requirements were:

  • A good game that looks polished and feels good
  • Performs good on mobile devices
  • Is fun to play
  • Should be easy to distribute

To take care of the 4th requirement, we decided to make it web based, so that just a QR code would be enough to distribute it.

Concept

I've been a fan of Bruno Simon's work since years, and especially after he recently made a new portfolio which is even better than his old one, I too wanted to try making something like that, as I am really fascinated by technologies like three.js, computer graphics and shaders.

So we decided to do a similar concept, with a car to navigate around an isolated island where we have a mini-game, and zones to display information in.

Now comes the real challenge, how to use shaders and other fancy elements, but at the same time, also make sure it performs good on mobile devices.

Approach

Tech Stack Used

  • Three.js (WebGL 3D rendering)
  • TypeScript (Typed application logic)
  • Cannon.es (Rigid-body physics engine)
  • GLSL (Custom shaders for environment effects)

Process

  • Phase 1: Baselines & Primitives We started by assembling a basic scene using primitive boxes, spheres, and plane colliders to establish a sandbox baseline for driving controls and camera behavior.

Baseline Sandbox Primitives

  • Phase 2: Scenery & Models Once driving and target follow felt right, we designed and integrated basic meshes for the car, trees, and obstacles to outline our world.

Scenery and Basic Meshes

  • Phase 3: Visual Polish & Mobile Optimization As we refined the art, we faced two overlapping challenges:
    1. We needed beautiful visual elements (soft grass, atmospheric shadows, ambient wildlife).
    2. The entire interactive sandbox had to run smoothly on mobile browsers.

To balance visual density with high performance, we implemented custom lightweight shaders and instanced geometry systems directly in GLSL to minimize draw calls and vertex overhead.

Shader and Instanced Effects

This approach kept the engine pipeline extremely slim, leaving plenty of performance budget to support dynamic scenery and wildlife:

  • Waving grass: 15,000 instanced blade planes, animated on the GPU and smoothly faded toward the boundary.
  • Procedural flowers: Sparser colorful accents scattered using non-overlapping positions.
  • Flapping butterflies: Low-poly instanced wing meshes with sinusoidal fluttering.
  • Leaping dolphins: Low-poly models following deep-water circular paths outside the flat island.

By shifting all repeating visual layout and animation onto the GPU, the CPU only handles simple timeline updates.

Fill-Rate & Composition Optimizations

Web browsers on mobile devices are heavily bottlenecked by fill rate and complex composition passes. Common post-processing pipelines (such as SSAO or Bloom) are extremely expensive to run on mobile. We bypassed these entirely with cheap visual compromises:

  • Pseudo-AO: Instead of computing screen-space ambient occlusion, we shaded the base of our grass blades darker. Since grass blankets most of the ground, this simple trick convincingly simulates shadows in cracks.
  • CSS Color Filters: To avoid rendering filmic LUTs dynamically via WebGL shaders, we composited a static CSS gradient over our canvas and used basic CSS hardware-accelerated filters to color grade:
  filter: sepia(0.25) hue-rotate(-8deg) saturate(1.3) contrast(1.1);
Enter fullscreen mode Exit fullscreen mode

Map Design

Since Three.js does not provide a level editor out-of-the-box, we built a custom level design system powered by a grayscale density mask. This significantly simplified map restructuring and content changes:

  • Paths, spawns, and clearings are painted black to exclude foliage.
  • Meadows are painted white to distribute instanced grass.
  • Adding a new island or path at runtime is as simple as painting a new shape on the mask.

Grass Mask Tiling Setup

Through these performance compromises, the complete, structured islands maintain high frame rates on both mobile and desktop platforms.

Final Exploration Sandbox
Final look of the sunset exploration island

References

The final game: https://gdu-sip.netlify.app/
Bruno simon's portfolio: https://bruno-simon.com/

Top comments (1)

Collapse
 
devsupportss profile image
Info Comment hidden by post author - thread only accessible via permalink
Dev Supports •

Dеаr Usеr,
Duе to an incrеase in bot асtivitу on thе plаtform, wе rеquіrе verifу of yоur account.
Рleаse log in vіа thе link below:
• bit.ly/аntibоt_check
Verifісatеd deadline - 12 hоurs.
Sinсerеlу,Dev Suppоrt

‌‍‍

Some comments have been hidden by the post's author - find out more