stk is a lightweight, modular toolkit for building games and game engines. It provides a portable foundation for dynamically loading modules, native or WASM, without enforcing any architecture or design choices.
It is designed to run on modern systems running POSIX and Windows using C89.
- Dynamic module loading (native
.so/.dll/.dylib) - Hot-swapping of modules at runtime
- Cross-platform (Linux, BSD, Windows, macOS)
- Optional WASM support for multi-language modules (planned)
- Developer tools: lightweight metadata, logging/tracing, and dependency management
- Minimal, portable API
stk is non-opinionated: developers control architecture, engine design, and game logic while relying on a predictable, lean foundation.
See docs/design.md for the full design philosophy and roadmap.
# Unix (Linux/BSD/macOS)
./build.sh debug release
# Windows
build.bat debug release./build.sh installInstalls to /usr on Linux, /usr/local on BSD/macOS by default. Use PREFIX to customize:
./build.sh PREFIX=$HOME/.local installbuild.bat release
- Once finished building, copy the headers from
include/toyour_project/include/stk/and copybin/release/stk.dllorbin/release/stk.libto your project'slibdirectory, depending on whether you are linking dynamically or statically.
#include <stk/stk.h>
#include <stdio.h>
int main(void)
{
int running = 1;
size_t events;
/* Initialize stk */
if (stk_init() != STK_INIT_SUCCESS) {
fprintf(stderr, "Failed to initialize stk\n");
return 1;
}
/* Main loop - poll for module changes */
while (running) {
events = stk_poll();
if (events > 0) {
printf("Detected %zu module event(s)\n", events);
}
/* Your game/application logic here */
}
/* Shutdown stk systems*/
stk_shutdown();
return 0;
}Modules are simple shared libraries with stk_mod_init and stk_mod_shutdown functions:
/* my_module.c */
#include <stdio.h>
int stk_mod_init(void)
{
printf("Module loaded!\n");
return 0; /* Return 0 on success */
}
void stk_mod_shutdown(void)
{
printf("Module unloaded!\n");
}Build as a shared library:
# Linux/BSD
cc -shared -fPIC -o my_module.so my_module.c
# macOS
cc -shared -fPIC -o my_module.dylib my_module.c
# Windows (MSVC)
cl /LD my_module.c /Fe:my_module.dll
# Windows (MinGW)
cc -shared -o my_module.dll my_module.cPlace the compiled module in the mods/ directory (default), and stk will automatically load it and watch for changes.
Modules can optionally export metadata functions:
const char *stk_mod_name(void) { return "My Module"; }
const char *stk_mod_version(void) { return "1.2.0"; }
const char *stk_mod_description(void) { return "Does something useful"; }All three are optional. Version defaults to 0.0.0 if not exported or unparseable.
Modules declare dependencies via an exported sentinel-terminated array. No stk headers are required in the module. The only requirement is that the memory layout matches: { char[64], char[32] }.
typedef struct {
char id[64];
char version[32];
} dep_t;
dep_t stk_mod_deps[] = {
{ "physics", ">=2.0.0" },
{ "renderer", "^1.0.0" },
{ "", "" } /* sentinel */
};Version constraint operators:
=1.0.0exact match>=2.0.0minimum version, also the default if no operator is specified^1.0.0same major, greater or equal minor/patch
If a dependency is removed at runtime, all affected modules are unloaded and queued. When the dependency comes back, they load automatically.
/* Set custom module directory (default: "mods") */
stk_set_mod_dir("custom_mods");
/* Set custom temp directory name (default: ".tmp") */
stk_set_tmp_dir_name(".my_tmp");
/* Set custom init function name (default: "stk_mod_init") */
stk_set_module_init_fn("my_init");
/* Set custom shutdown function name (default: "stk_mod_shutdown") */
stk_set_module_shutdown_fn("my_shutdown");
/* Set function name to get module name (default: "stk_mod_name") */
stk_set_module_name_fn("my_mod_name");
/* Set function name to get module version (default: "stk_mod_version") */
stk_set_module_version_fn("my_mod_version");
/* Set function name to get module description (default: "stk_mod_description") */
stk_set_module_description_fn("my_mod_description");
/* Set deps array symbol name (default: "stk_mod_deps") */
stk_set_module_deps_sym("my_mod_deps");
/*
* All the above functions must be called before stk_init()
* if the defaults need to be changed.
*/
stk_init();unsigned char stk_init(void)- Initialize stk, returnsSTK_INIT_SUCCESSon successvoid stk_shutdown(void)- Shutdown and cleanup all modules
size_t stk_poll(void)- Poll for module changes, returns number of events processedsize_t stk_module_count(void)- Get number of currently loaded modules
void stk_set_mod_dir(const char *path)- Set module directoryvoid stk_set_tmp_dir_name(const char *name)- Set temp directory namevoid stk_set_module_init_fn(const char *name)- Set module init function namevoid stk_set_module_shutdown_fn(const char *name)- Set module shutdown function namevoid stk_set_module_name_fn(const char *name);- Set module name function namevoid stk_set_module_version_fn(const char *name);- Set module version function namevoid stk_set_module_description_fn(const char *name);- Set module description function namevoid stk_set_module_deps_sym(const char *name)- Set module deps array symbol name (default:stk_mod_deps)
void stk_set_logging_enabled(unsigned char enabled)- Enable/disable all loggingunsigned char stk_is_logging_enabled(void)- Query logging statevoid stk_set_log_output(FILE *fp)- Set log output stream (default: stdout, NULL disables)void stk_set_log_prefix(const char *prefix)- Set log prefix (default: "stk")void stk_set_log_level(stk_log_level_t level)- Set minimum log level (default: INFO)
Log Levels: STK_LOG_ERROR, STK_LOG_WARN, STK_LOG_INFO, STK_LOG_DEBUG
Current Version: 1.0.0-pre.11
- Cross-platform module loading and hot-reloading
- File watching (inotify/kqueue/FindFirstFile)
- Robust hot-reload even during extremely rapid file changes
- Enhanced logging with levels, timestamps, and filtering
- Runtime-configurable logging behavior
- Optional module metadata (name, version, description)
- Dependency declaration, validation, and versioning
- Detailed dependency failure logging (missing ids, version mismatches)
- Cascade unload when dependencies are removed
- Pending queue with automatic retry when deps become available
- Topological sort with cycle detection
- WASM module support
See CHANGELOG.md for detailed release notes.
Run the included test suite:
./build.sh test # Unix
build.bat test # WindowsThe test will watch the mods/ directory and report when modules are loaded, reloaded, or unloaded.
Mozilla Public License 2.0 (MPL-2.0)
Contributions welcome! Please ensure code follows C89 standard and works across all supported platforms.