Gabriel Malenowitch
March 15, 2026 · Gabriel Malenowitch

Rebuilding Minecraft from scratch in 24 hours (without a game engine)

typescript
three.js
webgl
gamedev
procedural
performance
frontend
project

Rebuilding Minecraft from scratch in 24 hours (without a game engine)

The goal was simple on paper: recreate Minecraft’s core engineering in less than 24 hours, without Unity, without Godot, without any game engine. Just TypeScript, mathematics, and the browser.

This post is the written version of the video below — if you’d rather see the project working, the video shows each step in real time.

The final result runs in any browser — you can play right now:

▶ Play in the browser · View code on GitHub

An infinite world with dynamic chunks, a full day and night cycle with a starry sky, procedurally generated vegetation and trees, lighting shaders, and player physics.


Chapter 1 — 3D in the browser

How a square becomes a cube

A standard Cartesian plane has two axes: X (width) and Y (height). For 3D to exist, we need a third axis — Z. What makes the computer calculate and project this depth onto the flat screen is a pipeline of three matrices:

  • Projection Matrix — calculates perspective. It’s what “squeezes” the 3D world onto the screen, creating the illusion that distant objects are smaller.
  • Model Matrix — defines the position, rotation, and scale of each object in the game’s universe.
  • View Matrix — is the camera’s matrix. And here’s a counterintuitive detail: the camera never moves. To save processing, the computer moves the entire universe in the opposite direction. The camera is always the origin.

Three.js instead of raw WebGL

Going down to this level of manual mathematics is possible, but that wasn’t the goal here. Three.js is a JavaScript library that runs on top of WebGL — the browsers’ native API for 3D graphics — and abstracts all this matrix work. With it, you think in terms of objects, positions, and materials.


Chapter 2 — World generation

Simplex Noise

To generate terrain that’s neither flat nor completely chaotic, the right algorithm is Simplex Noise — an optimized version of Perlin Noise, both classic algorithms that generate noise maps with smooth transitions.

What matters is understanding what the algorithm delivers: for each coordinate (X, Z), it returns a smooth value between -1 and 1 representing the terrain’s elevation — without sudden jumps between neighboring points.


Chapter 3 — Storing the world without crashing the browser

Linear memory with Uint8Array

How do you store thousands of blocks without freezing the browser? JavaScript has low-level typed arrays — and we’ll use Uint8Array, an array of 8-bit integers that lives directly in linear memory, without the overhead of regular arrays.

Each chunk has 32 × 32 × 32 blocks. That’s 32,768 positions — each one being an integer that maps to a block type:

0 → air
1 → dirt
2 → stone
3 → grass
...

To access a block at position (x, y, z) within the chunk:

const index = x + z * CHUNK_SIZE + y * CHUNK_SIZE * CHUNK_SIZE;
const blockType = chunk[index];

The world is made up of several chunks, each one a Uint8Array. With the data structure defined, all it took was combining Simplex Noise with Three.js reading the array positions — and the terrain appeared.


Chapter 4 — Shaders, optimization, and procedural generation

Lighting

Instead of heavy shaders right from the start, the approach was simple directional lighting — the sun casts shadows on the blocks based on its angle. It works well and the processing cost is low.

Render distance and face culling

The first optimization rule: only process what the player can see.

  • Strict render distance: the game only loads chunks within a radius around the player. The rest is discarded from memory.
  • Face culling (meshing algorithm): faces between two solid blocks are never visible — there’s no point rendering them. The algorithm builds the mesh including only the faces exposed to air. In a dense chunk, this eliminates most of the geometry.

Procedural generation

The world is infinite because new chunks are generated on demand. Every frame, the game calculates the distance from the player to the edge of the loaded world. If it’s less than 32 blocks, a new chunk is generated in that direction. Since generating a chunk is heavy work, the processing runs in a separate Web Worker — without blocking the main thread.


Chapter 5 — Textures, vegetation, day and night

Texture Atlas

To add textures without multiplying materials, the strategy is the texture atlas: a single image with all the game’s textures side by side. The shader maps each block face to the correct region of that image. One material, many textures.

Vegetation and trees

After the terrain is generated, a second pass goes through it layer by layer. For each block whose top is in contact with air:

  • Vegetation: added randomly with a configurable probability.
  • Trees: a wood block is placed on the ground, the trunk is stacked to a random height, and the canopy is calculated as a mathematical sphere around the top — a defined radius, leaf blocks filling the volume.

Day and night cycle

  • The sun moves gradually. Since it already emits directional light, the world’s lighting changes automatically as it moves.
  • The moon is always on the opposite side from the sun.
  • The sky gradually darkens as the sun disappears over the horizon.
  • The stars gain opacity as the sky darkens — disappearing during the day, appearing at night.
  • Clouds are generated at the start and move continuously. When they leave the field of view, new ones are generated — giving the impression of wind.

Chapter 6 — Actions and final result

With the world ready, I added a hotbar for the player to select the active block and the actions of breaking and placing blocks.

When breaking a block, we noticed a problem: the entire chunk’s mesh was rebuilt — 32,768 blocks reprocessed to change a single one. The solution was to divide each chunk into 8 × 8 × 32 subchunks: when changing a block, only the corresponding subchunk is rebuilt — 2,048 blocks instead of 32,768.


This project existed to prove a point: the foundations of an open-world game aren’t magic — they’re data structures, linear mathematics, and well-chosen algorithms.

If you’re curious about any of the concepts here — Simplex Noise, the 3D matrix pipeline, or the meshing algorithm — let me know in the comments.

06
Comments

Leave a comment

Feedback, questions, opportunities — feel free.