It’s Minecraft Now: Analyzing rd-20090515
The biggest single-version delta in Minecraft’s early history, and the one where it gets its name.
One day after the first zombie stumbled across a flat stone plain, Markus “Notch” Persson shipped a version that would be almost unrecognizable to someone looking only at the file count. Nineteen files became twenty-eight. One thousand eight hundred and sixty-eight lines became two thousand six hundred and sixty-nine. And com.mojang.rubydung — the package name borrowed from an abandoned earlier project — became com.mojang.minecraft.
The game has its name.
rd-20090515 was released on May 14, 2009, exactly one day after the two rd-132xxx builds that established the voxel world and populated it with zombies. In that single day, Notch added terrain generation, a tile type system, particle effects, random tile ticks, and five new block types. He changed the tick rate from 60 TPS to 20 TPS — a value Minecraft would keep for the next seventeen years and counting. He cut the zombie count from 100 to 10. He added keyboard shortcuts for selecting block types to place.
This is the version where Minecraft stops being a tech demo with mobs and starts being a game with a world.
The Rename
Let us start with the smallest change that carries the most weight. Every Java file now lives under com.mojang.minecraft instead of com.mojang.rubydung. The entry point class is Minecraft.java instead of RubyDung.java. The window title presumably reads “Minecraft” instead of “RubyDung.”
RubyDung was a name Notch had used for an earlier voxel project that he abandoned. He reused the name for the initial prototype, the way you might name a new project folder “test” or “experiment” before you know what it is. By this version, he knew what it was. The rename is trivial in terms of code — every file gets a new package declaration, nothing else changes — but it marks the moment the project gained an identity separate from its prototype heritage.
This matters because names create commitment. A project called “RubyDung” is something you are noodling on. A project called “Minecraft” is something you are building.
Terrain: The End of Flat
The previous versions generated terrain by filling the bottom two-thirds of the world with solid blocks. Every column was the same height. The surface was a featureless plane extending to the world boundaries. It was a demonstration that blocks could be stored, rendered, and interacted with — not a place you would want to explore.
rd-20090515 introduces PerlinNoiseFilter, a diamond-square noise generator that produces heightmap data for terrain. The name is a misnomer — this is not Perlin noise in the mathematical sense (gradient noise on a lattice), but a diamond-square subdivision algorithm that iteratively refines a coarse random grid into smooth, natural-looking height variation. The name stuck, though, and Notch continued to call his noise generators “Perlin” throughout Minecraft’s early development.
The generation algorithm combines four noise maps:
- Two heightmaps at different frequencies, producing candidate surface heights.
- A “cave factor” map that selects between the two heightmaps per column, creating regions with different terrain character.
- A rock depth map that determines where solid rock begins beneath the surface.
For each column, the algorithm picks the higher of the two candidate heights (after the cave factor selection), divides by 8, and adds depth/3 (the old flat-world surface height). This produces gentle rolling hills that average around the same height as the old flat world but vary column to column.
Below the surface, three layers emerge:
- Grass at the exact surface height (a single block thick).
- Dirt between the surface and the rock depth.
- Rock below the rock depth, which is always at least 2 blocks below the surface.
This is the layer cake structure that every Minecraft player recognizes: grass on top, dirt underneath, stone at depth. It is simple compared to the multi-biome, cave-riddled terrain of modern Minecraft, but it establishes the fundamental principle that the world has geological strata, not just solid-or-air.
The diamond-square algorithm seeds a coarse grid with random values, then iteratively subdivides: averaging corners plus a random offset for center points (diamond step), then averaging edge midpoints plus a random offset (square step). Each iteration halves the step size and the offset magnitude, establishing large-scale features first and adding fine detail on top. The levels parameter controls initial coarseness: level 0 produces fine-grained variation (used for heightmaps), level 1 produces smoother, broader variation (used for the cave factor and rock depth).
The Tile Type System
In the previous two versions, there was exactly one solid block type. The world contained air (0) and solid (1). The Tile class was a render helper that knew how to draw the six faces of a cube, and the level just stored bytes.
rd-20090515 replaces this with a full tile type registry. Tile.tiles is a 256-element array where each index maps to a tile type instance. Seven types are registered:
| ID | Name | Solid | Blocks Light | Notes |
|---|---|---|---|---|
| 0 | Air | No | No | Not registered (null slot) |
| 1 | Rock | Yes | Yes | Basic stone, texture index 1 |
| 2 | Grass | Yes | Yes | Per-face textures, spreads/dies |
| 3 | Dirt | Yes | Yes | Texture index 2 |
| 4 | Stone Brick | Yes | Yes | Texture index 16 |
| 5 | Wood | Yes | Yes | Texture index 4 |
| 6 | Bush | No | No | Non-solid, X-shaped rendering, lifecycle |
This is the seed of the block registry that would eventually hold hundreds of block types. The architecture is notable for what it gets right from the start: each tile type has distinct properties (solidity, light blocking, texture, tick behavior) looked up by ID. The level stores only byte IDs. All behavior is centralized in the tile type objects. Adding a new block type means adding a new class and registering it at a new ID. The data storage layer is completely decoupled from the behavior layer.
The per-face texture system is particularly forward-looking. In the previous versions, each tile had one texture applied to all six faces. Grass in rd-20090515 has three: a green top (texture 0), a dirt bottom (texture 2), and a distinctive side texture (texture 3) with a green top edge fading into brown dirt. This is the classic Minecraft grass block appearance, recognizable to anyone who has played the game, and it was there from the very first version that had grass as a distinct block type.
Tile Behaviors: The World Comes Alive
Two tile types have tick behavior, driven by a new random tile tick system.
Grass has a simple but effective lifecycle:
- If a grass block is not lit (below the heightmap-determined light depth), it turns to dirt. Darkness kills grass.
- If a grass block is lit, it attempts to spread. Each tick, it makes four attempts to convert a nearby dirt block to grass. The target is picked randomly within a [-1, +1] horizontal range and a [-3, +1] vertical range. The vertical asymmetry is interesting: grass spreads downward up to 3 blocks but upward only 1. This biases spread down slopes, producing natural-looking grass coverage that flows downhill from lit surfaces into nearby shadowed overhangs.
The spread only succeeds if the target block is dirt and is lit. This creates a self-limiting system: grass cannot spread into caves or underneath overhangs that block light. Over time, all lit dirt surfaces become grass while all dark surfaces revert to dirt. The world reaches a stable equilibrium determined purely by its geometry and lighting.
Bush has a death condition but no spread:
- If a bush block is not lit, it dies (becomes air).
- If the block directly below a bush is not dirt or grass, it dies.
This means bushes can only survive on lit, vegetated or soil surfaces. They cannot float in the air, sit on stone, or grow in caves. They are the first block in Minecraft’s history with a dependency on the block below them — a pattern that would be repeated endlessly with flowers, crops, saplings, and many other blocks in future versions.
Bush rendering is also distinctive. Instead of drawing as a standard six-faced cube, bushes render as two intersecting quads forming an X shape when viewed from above. Both front and back faces are drawn for each quad, producing four visible surfaces. This is the classic “sprite-in-a-voxel-world” technique: a flat image that faces the viewer from any angle because it is drawn from two perpendicular planes. The bush is non-solid (no collision AABB, entities pass through it) and transparent to light.
Random Tile Ticks
The tick behaviors described above need a driver. That driver is the random tile tick system, introduced in Level.tick().
Each game tick, the level accumulates width * height * depth unprocessed units. It then divides by 400 to determine how many random tile updates to perform. For the standard 256x256x64 world, this produces approximately 10,486 random tile updates per game tick. Each update picks a random block position, checks if it is non-air, and calls the tile’s tick method.
This is probabilistic, not exhaustive. Not every block is ticked every frame — far from it. The world contains 256 * 256 * 64 = 4,194,304 blocks, and only ~10,000 are ticked per game tick. Each individual block has roughly a 0.25% chance of being ticked in any given game tick. Over time, all blocks will be ticked, but the timing is stochastic.
This design is elegant for several reasons. First, it is O(ticks) per game tick, not O(blocks). Processing every block every tick would be computationally ruinous for large worlds. Second, the randomness produces organic, gradual effects: grass does not spread in a uniform wave but in a stochastic scatter, creating natural-looking edges and coverage patterns. Third, it scales: if you double the world size, you double the tick count, maintaining roughly the same per-block tick rate.
The constant 400 is the tuning knob. A smaller value means more ticks per frame (faster spread, higher CPU cost). A larger value means fewer ticks (slower spread, lower cost). 400 was apparently the sweet spot Notch found for making grass spread at a visually satisfying rate without consuming too much frame time.
This random tick system survives to modern Minecraft essentially unchanged. The randomTickSpeed game rule controls it, defaulting to 3 random ticks per chunk section per game tick in modern versions — a different parameterization of the same concept.
Particles: Destruction Has Consequences
Destroying a block in the previous versions was silent and instantaneous: the block disappeared, leaving air. In rd-20090515, block destruction spawns particles.
Particle extends Entity — it has position, velocity, a bounding box, and collision resolution. But particles differ from entities in important ways:
- Much heavier gravity. Particles fall at 0.04 units per tick, eight times the 0.005 gravity applied to players and zombies. This produces a rapid, debris-like fall rather than the floaty arc of a walking entity.
- Different friction. Air drag is 0.98 on all axes (vs 0.91 horizontal for entities). Ground friction is 0.7 (vs 0.8 for entities). Particles lose energy faster on the ground and slower in the air, producing a scattering debris pattern that settles quickly.
- Finite lifetime. Each particle has a randomly determined lifetime between 4 and 40 ticks (0.2 to 2.0 seconds at 20 TPS). When age reaches lifetime, the particle marks itself as removed and the engine cleans it up.
- Tiny size. Particle bounding boxes are 0.2 x 0.2 units, compared to the 0.6 x 1.8 entity bounding box. They are small enough to fit into crevices and rest on ledges.
When a block is destroyed, the ParticleEngine spawns 64 particles arranged in a 4x4x4 grid within the block volume. Each particle is centered in its grid cell and given an initial velocity directed outward from the block center, normalized and scaled by a random speed factor. The result is a small explosion of debris that sprays outward, arcs downward under heavy gravity, and settles on nearby surfaces.
This is the first time an action in the game produces a visible, physics-driven response. Placing and destroying blocks were previously instantaneous state changes — the block was there, now it is not. Particles give destruction weight and consequence. You are not just flipping a bit in an array; you are breaking something, and the pieces go somewhere.
The Timer Change: 20 TPS
The Timer is now constructed with 20.0 instead of 60.0. This changes the game’s logic tick rate from 60 ticks per second to 20 ticks per second.
The code in Timer.java is unchanged — the tick rate was always a constructor parameter. But the consequences ripple through every system that operates in per-tick units. Player gravity of 0.005 per tick now means 0.1 units per second instead of 0.3 units per second. Jump velocity of 0.12 per tick means a jump that takes fewer real-time ticks to resolve. Friction constants that damp velocity by percentages per tick now damp less per wall-clock second.
Does this change how the game feels? Absolutely. At 60 TPS, physics are smooth and fine-grained. At 20 TPS, each tick covers three times as much wall-clock time, making individual physics steps larger and more visible. The render interpolation system (computing positions between ticks using partial_tick) smooths the visual result, but the underlying simulation is coarser.
Why 20 TPS? It was likely a performance decision. The tile tick system added in this version processes thousands of random blocks per game tick. At 60 TPS, that would be ~630,000 random tile updates per second. At 20 TPS, it is ~210,000. The particle system and additional game logic also benefit from the reduced tick rate. And 20 TPS turned out to be good enough — it became the standard tick rate for all of Minecraft’s future development, never changed even as hardware improved by orders of magnitude.
This is one of those early engineering decisions that becomes load-bearing for an entire ecosystem. Redstone circuits, mob spawning, crop growth, entity physics, command blocks, datapacks — they all operate in 20 TPS units. Changing it now would break virtually every Minecraft creation ever built.
Ten Zombies, Not a Hundred
The zombie count drops from 100 to 10. This is probably another performance concession. With the new terrain generation, tile ticks, and particles all consuming CPU time, 100 entities with full collision resolution every tick was likely noticeable.
The surviving zombies now have resetPos() called after creation, scattering them across the map rather than clustering at the world center. The zombie AI is completely unchanged — same random walk, same physics, same jump probability. The key G allows spawning additional zombies at the player’s position.
DirtyChunkSorter and the Applet Wrapper
Two smaller additions round out the version. DirtyChunkSorter sorts dirty chunks by distance to the player before rebuilding, ensuring nearby terrain updates are visible first — a foreshadowing of the distance-based priority systems that pervade modern Minecraft. MinecraftApplet.java is a trivial Applet wrapper that allowed the game to run in web browsers via the Java plugin, the distribution mechanism that would power Minecraft’s initial viral spread.
What Did NOT Change
Twelve of the nineteen files from rd-132328 are byte-identical:
- The entire character model system (
Vec3,Vertex,Polygon,Cube) is unchanged. - Collision primitives (
AABB) are unchanged. Player.javais unchanged. Same physics, same input handling.Zombie.javais unchanged. Same AI, same model, same animation.HitResult,Textures,LevelListener,Frustum,Tesselatorare unchanged.
The entity system built yesterday carried through today without modification. The character model system built yesterday is still rendering the same zombie bodies. The collision system built two days ago is still resolving the same axis-separated sweeps.
This is the compounding value of clean architecture. Each version adds new systems without disturbing existing ones. The tile type registry slots in above the level data layer. The particle system slots in beside the entity system. The terrain generator replaces the flat fill without changing how blocks are stored or rendered. The pieces are independent enough that new ones can be added without disturbing old ones.
The Shape of Things
rd-20090515 is the version where Minecraft’s architectural skeleton is complete. It has:
- A voxel world with varied terrain
- Multiple block types with distinct properties
- Block types that change over time (grass spreading, bushes dying)
- A tile type registry that can be extended with new types
- Entities with physics and AI
- A particle system for visual feedback
- A 20 TPS tick rate
- Save/load persistence
- Block placement with type selection
- Browser deployment via applet
What it does not have yet: crafting, inventory, survival, health, hunger, day/night cycles, hostile mob behavior, redstone, water, lava, or any of the systems that make Minecraft a game rather than a sandbox. But the infrastructure to support all of those things is here. The tile registry will hold hundreds of block types. The entity system will support dozens of mob types. The random tick system will drive crop growth and fire spread. The particle engine will handle rain, snow, lava drips, and enchantment sparkles.
Notch built this in a day. Twenty-eight files, 2,669 lines, a complete game engine with terrain, entities, particles, and tile behaviors — assembled approximately 48 hours after the first commit.
The name “Minecraft” appeared on this day, but so did the architecture that would support the best-selling game of all time. The world has hills. The grass spreads in the sun and dies in the dark. The stage is set.