Smile stands for Simple Modularity Is Low-Key Elegant, and it's a
lightweight collection of modules that simplifies 2D game development.
Ideal for game jams and rapid prototyping, Smile provides clean
abstractions that keep your code lean, organized, and fully under your control.
Smile is a modular collection of C libraries that streamline common 2D
game-development tasks such as managing scenes, simulating particles, and
saving or loading data. It's supported on Windows and Mac (Linux untested
but POSIX-compliant) and built for developers who want simplicity without
sacrificing control.
You can mix and match only the modules you need (for example, using SceneManager without ParticleSystem) to keep your project lightweight and focused. And while Smile doesn’t handle rendering, input, or audio directly, it integrates seamlessly with libraries like raylib.
Before building Smile, make sure you have the following installed:
CMake3.30 or higher- A build tool such as
MakeorNinja - A C compiler with C23 support such as
ClangorGCC
From your game directory, run:
git clone https://github.com/vitorbetmann/smile.git
cmake -S smile -B smile/build
cmake --build smile/buildSmile builds as a static library (libsmile.a on Mac/Linux, smile.lib on Windows) containing all Smile modules that you can link directly into your game.
A typical project structure might look like this:
/my_game_project/
├── main.c # Your game's entry point
└── smile/ # Smile cloned here
By default, Smile compiles with runtime warning and info logs enabled.
Below is an example of how they would appear in your terminal:
If you want to disable them, pass the following flags when configuring your build with CMake:
cmake -S ./smile -B smile/build -DSMILE_LOG_WARNING=OFF -DSMILE_LOG_INFO=OFFThis will disable all Smile warning and info logging output at build
time. Error logs cannot be disabled.
There are two common ways to compile your game using Smile:
clang main.c -Ismile/include -Lsmile/build -lsmile -o my_gameIf needed, replace main.c with your entry source file and/or my_game with
your desired output name.
Your project directory should look like this:
/my_game_project/
├── CMakeLists.txt # Your game's CMake file
├── main.c # Your game's entry point
└── smile/ # Smile cloned or copied here
In your CMakeLists.txt, add:
# Add Smile as a subdirectory
add_subdirectory(smile)
# Include Smile headers
target_include_directories(my_game PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/smile/include
)
# Link against the Smile static library
target_link_libraries(my_game PRIVATE smile)If needed, replace my_game with the name of your project's executable, and you
can compile your game normally using cmake.
Okay, now that you have cloned and built Smile, what next?
Below is an example of how to use the SceneManager module. It follows a set of conventions shared across modules, making it easy to learn new ones:
#include "SceneManager.h"
#include "Menu.h" // Define your scenes in other files.
#include "LevelOne.h"
int main(void)
{
/* Most modules have a Start function. The first 2 letter preceding 'Start'
* serve to identify from which module that function belongs (sm for
* SceneManager, sl for SaveLoad, lg for Log...)
*/
smStart();
// Pass in the scenes' functions into smCreateScene.
smCreateScene("menu", menuEnter, menuUpdate, menuDraw, menuExit);
smCreateScene("level 1", levelOneEnter, levelOneUpdate, levelOneDraw, levelOneExit);
smSetScene("menu", nullptr); // Choose where you want to start
while (smIsRunning()) // Run your game until you Stop SceneManager
{
float dt = smGetDt(); // Calculate the delta time since the last frame
smUpdate(dt); // Update game logic
smDraw(); // Render to the screen
}
}Without all the comments, this is how short your main.c file can be:
#include <SceneManager.h>
#include "menu.h"
#include "levelOne.h"
int main(void)
{
smStart();
smCreateScene("menu", menuEnter, menuUpdate, menuDraw, menuExit);
smCreateScene("level 1", levelOneEnter, levelOneUpdate, levelOneDraw, levelOneExit);
smSetScene("menu", nullptr);
while (smIsRunning())
{
smUpdate(smGetDt());
smDraw();
}
}Then in your scenes' header files you could have something like:
#ifndef MENU_H
#define MENU_H
void menuEnter(void *args);
void menuUpdate(float dt);
void menuDraw(void);
void menuExit(void);
#endifAnd in the source files:
#include "menu.h"
#include "SceneManager.h"
void menuEnter(void *args)
{
// Handle initialization
}
void menuUpdate(float dt)
{
// Handle inputs and updates
// Changing scenes is easy after they're created:
if (PlayButtonPressed())
{
smSetScene("level 1", nullptr);
}
// So is quitting the game:
else if (QuitButtonPressed())
{
smStop(); /* This calls this scene's exit function and sets smIsRunning
* to false, breaking the main game loop.
* Most modules have a Stop function as well. Therefore, the
* workflow of Start → Use → Stop is common, making it easy to
* pick up and learn other modules.
*/
}
}
void menuDraw(void)
{
// Handle rendering
}
void menuExit(void)
{
// Handle cleanup
}It's as simple as that! All the rest is handled by SceneManager.
And this is the overall philosophy of Smile. It handles the boilerplate in the background so you can focus on letting your creativity out!
If you're interested, feel free to explore each module for detailed guides and examples:
| Module | Description |
|---|---|
| Log | Debug code and handle fatal errors easily |
| ParticleSystem (🚧 Under Development) | Simulate smoke, dust, fire, and more |
| SaveLoad (🚧 Under Development) | Quickly save and load your game |
| SceneManager | Manage scenes and transitions cleanly |
"I built Smile to be the open source project I wish I had in my early programming days.
1. Low barrier of entry
2. Well documented
3. Learning-focused"— Vitor Betmann, creator of Smile
Smile is an open learning project. Everyone is welcome to use Smile to learn, suggest improvements, and help it evolve.
That said, Smile is also a personal sandbox project I’m building to understand how game frameworks work from the ground up. I reserve some systems to design and architect myself first as part of that learning journey and once those foundations are ready, contributions that improve, expand, or refine them are always welcome.
If that got you excited, there are many ways to contribute (plus, you'll get full credit in the code and Git history!):
- Suggesting improvements/optimizations
- Adding features
- Writing/editing documentation
- Making games and reporting bugs
To learn more, check out the Contributing Guide.
Smile is released under the MIT License. See the LICENSE file for details.
| Last modified | Author (username) | Description |
|---|---|---|
| Feb 17, 2026 | vitorbetmann | Renamed StateMachine to SceneManager; |




