Want to take your software engineering career to the next level? Join the mailing list for career tips & advice Click here


A simple Minecraft clone written in C using modern OpenGL (shaders).

Subscribe to updates I use Craft

Statistics on Craft

Number of watchers on Github 4725
Number of open issues 60
Average time to close an issue 4 days
Main language C
Average time to merge a PR 5 days
Open pull requests 20+
Closed pull requests 40+
Last commit over 3 years ago
Repo Created over 7 years ago
Repo Last Updated over 2 years ago
Size 14.1 MB
Homepage http://www.michae...
Organization / Authorfogleman
Latest Releasev1.0
Page Updated
Do you use Craft? Leave a review!
View open issues (60)
View Craft activity
View on github
Book a Mock Interview With Me (Silicon Valley Engineering Leader, 100s of interviews conducted)
Software engineers: It's time to get promoted. Starting NOW! Subscribe to my mailing list and I will equip you with tools, tips and actionable advice to grow in your career.
Evaluating Craft for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)


Minecraft clone for Windows, Mac OS X and Linux. Just a few thousand lines of C using modern OpenGL (shaders). Online multiplayer support is included using a Python-based server.




  • Simple but nice looking terrain generation using perlin / simplex noise.
  • More than 10 types of blocks and more can be added easily.
  • Supports plants (grass, flowers, trees, etc.) and transparency (glass).
  • Simple clouds in the sky (they don't move).
  • Day / night cycles and a textured sky dome.
  • World changes persisted in a sqlite3 database.
  • Multiplayer support!


Mac and Windows binaries are available on the website.


See below to run from source.

Install Dependencies

Mac OS X

Download and install CMake if you don't already have it. You may use Homebrew to simplify the installation:

brew install cmake

Linux (Ubuntu)

sudo apt-get install cmake libglew-dev xorg-dev libcurl4-openssl-dev
sudo apt-get build-dep glfw


Download and install CMake and MinGW. Add C:\MinGW\bin to your PATH.

Download and install cURL so that CURL/lib and CURL/include are in your Program Files directory.

Use the following commands in place of the ones described in the next section.

cmake -G "MinGW Makefiles"

Compile and Run

Once you have the dependencies (see above), run the following commands in your terminal.

git clone https://github.com/fogleman/Craft.git
cd Craft
cmake .


Register for an account!



You can connect to a server with command line arguments...

./craft craft.michaelfogleman.com

Or, with the /online command in the game itself.

/online craft.michaelfogleman.com


You can run your own server or connect to mine. The server is written in Python but requires a compiled DLL so it can perform the terrain generation just like the client.

gcc -std=c99 -O3 -fPIC -shared -o world -I src -I deps/noise deps/noise/noise.c src/world.c
python server.py [HOST [PORT]]


  • WASD to move forward, left, backward, right.
  • Space to jump.
  • Left Click to destroy a block.
  • Right Click or Cmd + Left Click to create a block.
  • Ctrl + Right Click to toggle a block as a light source.
  • 1-9 to select the block type to create.
  • E to cycle through the block types.
  • Tab to toggle between walking and flying.
  • ZXCVBN to move in exact directions along the XYZ axes.
  • Left shift to zoom.
  • F to show the scene in orthographic mode.
  • O to observe players in the main view.
  • P to observe players in the picture-in-picture view.
  • T to type text into chat.
  • Forward slash (/) to enter a command.
  • Backquote (`) to write text on any block (signs).
  • Arrow keys emulate mouse movement.
  • Enter emulates mouse click.

Chat Commands

/goto [NAME]

Teleport to another user. If NAME is unspecified, a random user is chosen.


Display a list of connected users.

/login NAME

Switch to another registered username. The login server will be re-contacted. The username is case-sensitive.


Unauthenticate and become a guest user. Automatic logins will not occur again until the /login command is re-issued.

/offline [FILE]

Switch to offline mode. FILE specifies the save file to use and defaults to craft.

/online HOST [PORT]

Connect to the specified server.

/pq P Q

Teleport to the specified chunk.


Teleport back to the spawn point.



Implementation Details

Terrain Generation

The terrain is generated using Simplex noise - a deterministic noise function seeded based on position. So the world will always be generated the same way in a given location.

The world is split up into 32x32 block chunks in the XZ plane (Y is up). This allows the world to be infinite (floating point precision is currently a problem at large X or Z values) and also makes it easier to manage the data. Only visible chunks need to be queried from the database.


Only exposed faces are rendered. This is an important optimization as the vast majority of blocks are either completely hidden or are only exposing one or two faces. Each chunk records a one-block width overlap for each neighboring chunk so it knows which blocks along its perimeter are exposed.

Only visible chunks are rendered. A naive frustum-culling approach is used to test if a chunk is in the cameras view. If it is not, it is not rendered. This results in a pretty decent performance improvement as well.

Chunk buffers are completely regenerated when a block is changed in that chunk, instead of trying to update the VBO.

Text is rendered using a bitmap atlas. Each character is rendered onto two triangles forming a 2D rectangle.

Modern OpenGL is used - no deprecated, fixed-function pipeline functions are used. Vertex buffer objects are used for position, normal and texture coordinates. Vertex and fragment shaders are used for rendering. Matrix manipulation functions are in matrix.c for translation, rotation, perspective, orthographic, etc. matrices. The 3D models are made up of very simple primitives - mostly cubes and rectangles. These models are generated in code in cube.c.

Transparency in glass blocks and plants (plants dont take up the full rectangular shape of their triangle primitives) is implemented by discarding magenta-colored pixels in the fragment shader.


User changes to the world are stored in a sqlite database. Only the delta is stored, so the default world is generated and then the user changes are applied on top when loading.

The main database table is named block and has columns p, q, x, y, z, w. (p, q) identifies the chunk, (x, y, z) identifies the block position and (w) identifies the block type. 0 represents an empty block (air).

In game, the chunks store their blocks in a hash map. An (x, y, z) key maps to a (w) value.

The y-position of blocks are limited to 0 <= y < 256. The upper limit is mainly an artificial limitation to prevent users from building unnecessarily tall structures. Users are not allowed to destroy blocks at y = 0 to avoid falling underneath the world.


Multiplayer mode is implemented using plain-old sockets. A simple, ASCII, line-based protocol is used. Each line is made up of a command code and zero or more comma-separated arguments. The client requests chunks from the server with a simple command: C,p,q,key. C means Chunk and (p, q) identifies the chunk. The key is used for caching - the server will only send block updates that have been performed since the client last asked for that chunk. Block updates (in realtime or as part of a chunk request) are sent to the client in the format: B,p,q,x,y,z,w. After sending all of the blocks for a requested chunk, the server will send an updated cache key in the format: K,p,q,key. The client will store this key and use it the next time it needs to ask for that chunk. Player positions are sent in the format: P,pid,x,y,z,rx,ry. The pid is the player ID and the rx and ry values indicate the players rotation in two different axes. The client interpolates player positions from the past two position updates for smoother animation. The client sends its position to the server at most every 0.1 seconds (less if not moving).

Client-side caching to the sqlite database can be performance intensive when connecting to a server for the first time. For this reason, sqlite writes are performed on a background thread. All writes occur in a transaction for performance. The transaction is committed every 5 seconds as opposed to some logical amount of work completed. A ring / circular buffer is used as a queue for what data is to be written to the database.

In multiplayer mode, players can observe one another in the main view or in a picture-in-picture view. Implementation of the PnP was surprisingly simple - just change the viewport and render the scene again from the other players point of view.

Collision Testing

Hit testing (what block the user is pointing at) is implemented by scanning a ray from the players position outward, following their sight vector. This is not a precise method, so the step rate can be made smaller to be more accurate.

Collision testing simply adjusts the players position to remain a certain distance away from any adjacent blocks that are obstacles. (Clouds and plants are not marked as obstacles, so you pass right through them.)

Sky Dome

A textured sky dome is used for the sky. The X-coordinate of the texture represents time of day. The Y-values map from the bottom of the sky sphere to the top of the sky sphere. The player is always in the center of the sphere. The fragment shaders for the blocks also sample the sky texture to determine the appropriate fog color to blend with based on the blocks position relative to the backing sky.

Ambient Occlusion

Ambient occlusion is implemented as described on this page:



  • GLEW is used for managing OpenGL extensions across platforms.
  • GLFW is used for cross-platform window management.
  • CURL is used for HTTPS / SSL POST for the authentication process.
  • lodepng is used for loading PNG textures.
  • sqlite3 is used for saving the blocks added / removed by the user.
  • tinycthread is used for cross-platform threading.
Craft open issues Ask a question     (View All Issues)
  • about 4 years Asset licenses?
  • over 4 years Ncurses render option
  • almost 5 years How can I solve this problme while I used linux ?
  • about 5 years Cursor drifts up during gameplay
  • over 5 years Attach binaries to the release
  • almost 6 years Game needs name change for more id and support
  • almost 6 years Fullscreen seems not to work on OSX 10.10
  • almost 6 years Immediate segmentation violation
  • almost 6 years Some questions for the uninitiated
  • about 6 years Decrease size of DB
  • about 6 years Attempting to place a block next to another player as a guest makes the current block there transparent
  • about 6 years Build broken in OS X Yosemite ...
  • about 6 years Compiling on Windows 7 with MinGW, missing symbols
  • over 6 years Craft leaves connection open to first server while connected to second server and will crash if the first server terminates.
  • over 6 years Is the project dead?
  • over 6 years [Linux] Crashes X using nouveau
  • over 6 years Completion of error handling
  • over 6 years Improve const-correctness
  • over 6 years Third-Person camera
  • almost 7 years Make the Server more gerneric and configurable
  • almost 7 years Cursor is moving after you resize Craft main window
  • almost 7 years Craft crashes on win7 when you minimze it's window.
  • almost 7 years Make light sources an actual block
  • almost 7 years Synchronize the time of day between the client and server
  • almost 7 years Add an auto-updater
  • almost 7 years Save time of day in db
  • almost 7 years Save, user changed, view distance in db
  • almost 7 years [enhancement] Add compas
  • almost 7 years Suggestion: Add direction to the state of a block
  • almost 7 years Port builder.py to C
Craft open pull requests (View All Pulls)
  • Add: LAN mode with fixed hour (option), user defined nicknames
  • Implement a lua scripting api
  • Update README.md
  • added support for Visual Studio 2013
  • Fixed Division by 0 when minimizing window
  • Running at ctrl+w
  • Allow configuring distance to display player name at
  • Orthographic view: zoom w/ scrollwheel, or keyboard
  • corrected types of static arrays
  • Add key shortcuts to toggle debug/UI
  • Add key shortcut to descend when flying
  • Add key shortcut to toggle fullscreen/windowed mode
  • Port to run Craft in web browser using Emscripten
  • Fix placing blocks on plants or other non-obstacles (simple fix)
  • Added support FreeBSD
  • server.py works with python 3
  • Fix185
  • fix #186
  • Add doxygen for C
  • Update README.md
Craft questions on Stackoverflow (View All Questions)
  • Craft CMS With Php/Nginx on Docker can't write outside Document Root
  • How to craft simple defer on success of JQuery statement
  • Craft CMS with other Yii2 Applications
  • Craft - Order by title that is a number
  • How to craft an entity in XSLT
  • Application Craft, Parse and PhoneGap
  • Retreiving data from DB in application craft
  • How we can allow permit ion to access craft/app in Craft CMS?
  • How to craft specific packets on the host of Mininet to generate massive Packet-In messages
  • Craft amplifyjs GET request with body
  • craft a javascript closure for ajax call in google map example
  • Craft a JSONpath expression so that it retrieves only a specific value?
  • Computer Craft modem.open( ) command giving me "attempt to index ? (a nil value)"
  • How to Fix Error 403 Attempting to Access Craft Admin Page Using XAMPP
  • Craft Calendars Performance Issues
  • Git: How to manually manipulate/craft a merge between two branches when no conflict occurs
  • How to craft a regex for processing a source file, where the search pattern is built from function name?
  • Multi-threading functions in Computer Craft
  • Craft calculator loop
  • Can't craft valid IAM SSL Certificate for Cloudfront
  • How does one craft an array from LEFT JOINs when joined tables have multiple matches and GROUP BY omits needed rows
  • Setting the link property in Application Craft
  • Kendo UI vs Application Craft
  • Could I craft ethernet frame with wrong FCS/CRC?
  • How do I craft a regular expression to exclude strings with parentheses
  • craft handmade x86 assembly in allocated memory
  • Turing's Craft exercise stumped me... seems too easy
  • Lua os.date() function not working in Computer Craft
  • How to analyze/craft packets before they are sent/received?
  • Is it possible to craft a Python dict with all (or most) of the properties of a dict with Abstract Base Classes?
Craft list of languages used
Other projects in C
Powered by Autocode - Instant Webhooks, Scripts and APIs
Autocode logo wordmark