skele

License: MPL 2.0

skele is a lightweight, generic game framework written in C99. It provides a platform-agnostic core (clock, video, input) split cleanly from OS/backend-specific implementations, so games and engines built on it stay portable without fighting the framework's opinions.

It pairs naturally with stk for hot-reloadable game modules, but has no hard dependency on it beyond the optional skele_stk_setup/skele_stk_teardown glue.


Key Features

  • Platform-agnostic core (include/) with OS/backend-specific implementations swapped in at build time (src/platform/)
  • Two video backends behind one API: software/SDL3 blit (libskele) and OpenGL (libglskele)
  • Headless server builds, linking only the engine core, no client/video/input code pulled in
  • Fixed-timestep clock with monotonic time and signal-aware sleep (POSIX and Win32)
  • SDL3-backed input: keyboard, gamepad (up to 4 pads), mouse, with held/pressed-this-frame state and analog axes
  • 256-color palette + software blit path for indexed-color renderers (Doom-era style pipelines)
  • Optional stk hot-reload integration via skele_stk_setup/skele_stk_teardown

Quick Start

Building

# Unix (Linux/BSD/macOS)
./build.sh debug release

# Windows
build.bat debug release

Builds three static libraries into bin/{debug,release}:

  • libskele.a - software/SDL3 client backend
  • libglskele.a - OpenGL client backend
  • libskeleserver.a - headless engine core only

Raspberry Pi 5 is auto-detected and builds against GL 3.1 instead of the default 3.3.

Installation

Unix (Linux/BSD/macOS)

./build.sh install

Installs to /usr on Linux, /usr/local on BSD/macOS by default. Use PREFIX to customize:

./build.sh PREFIX=$HOME/.local install

Windows

build.bat release
  • Once finished building, copy the headers from include/ to your_project/include/skele/ and copy the built .lib/.dll files to your project's lib directory.

Usage

Basic Example (software client)

#include "client/blit.h"
#include "client/input.h"
#include "client/video.h"
#include "clock.h"
#include "skele.h"
#include <stdlib.h>
#include <stk/stk.h>

static uint8_t running = 1;

static void on_signal(void) { running = 0; }

int main(void)
{
    skele_video_config_t video_cfg;
    uint64_t last, now, elapsed, accum = 0;
    uint8_t *pixels;

    skele_clock_init(on_signal);

    if (skele_stk_setup() != SKELE_INIT_SUCCESS)
        return 1;

    if (skele_init() != SKELE_INIT_SUCCESS) {
        skele_stk_teardown();
        return 1;
    }

    video_cfg.render_width = SKELE_DEFAULT_RENDER_WIDTH;
    video_cfg.render_height = SKELE_DEFAULT_RENDER_HEIGHT;
    video_cfg.window_width = 0;
    video_cfg.window_height = 0;
    video_cfg.flags = 0;

    if (skele_video_init(video_cfg) != SKELE_INIT_SUCCESS) {
        skele_stk_teardown();
        skele_shutdown();
        return 1;
    }

    pixels = calloc(video_cfg.render_width * video_cfg.render_height,
                     sizeof(uint8_t));

    last = skele_time_ns();

    while (running) {
        stk_poll();
        if (!skele_input_poll())
            break;

        now = skele_time_ns();
        elapsed = now - last;
        accum += elapsed;
        last = now;

        while (accum >= skele_tick_ns) {
            skele_tick();
            accum -= skele_tick_ns;
        }

        skele_video_blit(pixels);
        skele_video_present();
    }

    free(pixels);
    skele_video_shutdown();
    skele_stk_teardown();
    skele_shutdown();
    return 0;
}

See example/client, example/gl_client, and example/server for the full reference loops, including a fixed-timestep accumulator suitable for interpolated rendering.

Headless / Server Builds

Link libskeleserver.a instead of libskele.a/libglskele.a to get the engine core (clock, tick, stk glue) without pulling in any video/input/SDL3 dependency:

cc -o my_server main.c -lskeleserver -lstk

API Reference

Core (skele.h)

  • uint8_t skele_init(void) / void skele_shutdown(void) - engine lifecycle
  • void skele_tick(void) - advance one simulation tick
  • void skele_set_tick_rate(uint8_t rate) - configure ticks/sec (default SKELE_DEFAULT_TICK_RATE)
  • uint64_t skele_tick_ns - nanoseconds per tick, for accumulator loops
  • uint8_t skele_stk_setup(void) / void skele_stk_teardown(void) - wire up stk hot-reload

Clock (clock.h)

  • void skele_clock_init(void (*on_signal)(void)) - monotonic clock + signal handling
  • uint64_t skele_time_ns(void) - current monotonic time
  • void skele_sleep_ns(uint64_t ns) - sleep for a duration

Video (client/video.h)

  • uint8_t skele_video_init(skele_video_config_t cfg) / void skele_video_shutdown(void)
  • void skele_video_present(void) - present the current frame
  • void skele_video_set_title(const char *title)
  • void skele_video_toggle_fullscreen(void) / skele_video_set_fullscreen_kind(...)
  • void skele_video_cycle_scale(void) - cycle integer window scale
  • void skele_video_set_mouse_grab(uint8_t grab)

Blit / Palette (client/blit.h, client/palette.h)

  • void skele_video_blit(uint8_t *pixels) - blit an indexed-color framebuffer through the active palette
  • void skele_palette_set(skele_palette_t pal) / skele_palette_set_index(uint8_t index, uint32_t color)

Input (client/input.h)

  • uint8_t skele_input_poll(void) - pump platform events, returns 0 on quit
  • uint8_t skele_key_down(skele_key_t key) / skele_key_held(skele_key_t key) - pressed-this-frame vs. currently-held
  • uint8_t skele_pad_connected(uint8_t pad), skele_pad_button_down/held(...), float skele_pad_axis(...) - up to SKELE_MAX_PADS gamepads
  • void skele_mouse_delta(int32_t *dx, int32_t *dy), skele_mouse_button_down/held(...)

Project Status

Current Version: 0.0.0

Early/active development. Platform backends (clock, video, input) are functional and exercised by real client applications, but the engine core (skele_init/skele_tick) is still minimal. API is not yet stable; expect breaking changes until the core lifecycle is fleshed out.

No test suite yet.


License

Mozilla Public License 2.0 (MPL-2.0)


Contributing

Contributions welcome! Please ensure code follows C99 standard and works across all supported platforms.

S
Description
Generic game engine framework
Readme MPL-2.0
98 KiB
Languages
C 71.2%
Makefile 26.5%
Shell 2%
Batchfile 0.3%