Search by

jovian / sdl3

projectsaturnstudios

Typed PHP projection of The PHP SDL3 Extension

0.8.x-dev 2026-09-17 17:32 UTC

This package is auto-updated.

Last update: 2026-09-17 17:33:44 UTC


README

Typed PHP projection of ext-sdl3.

jovian/sdl3 0.8.0 projects ext-sdl3 0.8.0, which links SDL 3.4.4. The Composer constraint is ext-sdl3: ^0.8.0.

ext-sdl3  →  jovian/sdl3  →  venusian-sdl3  →  Surface
1:1 binding  enums +         composition       cross-platform
+ glue       typed surface

What it is

ext-sdl3 binds SDL3 one-to-one but exposes no PHP-visible constants at all — 29 classes, zero functions, zero class constants — and hands back a bare int for every enum, flag and handle alike. This package adds the two things that are missing and nothing else:

  • 39 enum families / 836 cases, mined from the SDL3 C headers, each case annotated with the C constant it came from and verified against a C compiler.
  • Types on the surface: 76 parameters and 26 returns that were int now say which family they belong to.

Everything else is a faithful 1:1 forward. One PHP method, one extension call, same arguments in the same order. No behaviour is added — no exceptions, no reshaped returns, no invented defaults.

Input for venusian-sdl3's input.sdl3 engine comes through here as-is: keyboard, mouse and gamepad calls, event reads, and SDLEvents::SDLWaitEventTimeout(int $ms): ?array (['ptr', 'event_type'] or null), which lets a stage that owns the macOS event pump wait for input.

Install

composer require jovian/sdl3

Requires PHP 8.4+ and the sdl3 extension. Under Laravel Herd, PHP needs to be told where to find it:

export HERD_PHP_84_INI_SCAN_DIR=$(zsh -ic 'echo $HERD_PHP_84_INI_SCAN_DIR')
php --ri sdl3        # should report 0.8.0

Use

use Jovian\Bindings\Sdl3\SDL;
use Jovian\Bindings\Sdl3\SDLError;
use Jovian\Bindings\Sdl3\Video\SDLVideo;
use Jovian\Bindings\Sdl3\Render\SDLRender;
use Jovian\Bindings\Sdl3\Enums\SDLInitFlags;
use Jovian\Bindings\Sdl3\Enums\SDLWindowFlags;

if (!SDL::SDLInit(SDLInitFlags::VIDEO->value)) {
    throw new RuntimeException(SDLError::SDLGetError());
}

$window = SDLVideo::SDLCreateWindow('hello', 640, 480, SDLWindowFlags::RESIZABLE->value);
$renderer = SDLRender::SDLCreateRenderer($window);

SDLRender::SDLSetRenderDrawColor($renderer, 12, 34, 56, 255);
SDLRender::SDLRenderClear($renderer);
SDLRender::SDLRenderPresent($renderer);

SDLRender::SDLDestroyRenderer($renderer);
SDLVideo::SDLDestroyWindow($window);
SDL::SDLQuit();

Three things in that snippet are worth knowing.

Bitmask families take ->value. PHP enum cases cannot be OR'd, so parameters that take a bitmask stay int and you pass the case's value: SDLInitFlags::VIDEO->value | SDLInitFlags::EVENTS->value. True enumerations are different — those parameters accept either form:

SDLRender::SDLCreateTexture($r, SDLPixelFormat::RGBA8888, SDLTextureAccess::TARGET, 16, 16);
SDLRender::SDLCreateTexture($r, SDLPixelFormat::RGBA8888->value, 2, 16, 16);  // same call

Handles are raw pointers as PHP ints, and you own them. A failed creator returns 0, not null. Nothing releases anything for you.

Failure is SDL's convention, not PHP's. false / 0 / '' plus a message in SDLError::SDLGetError(). This package never throws — turning that into exceptions is venusian-sdl3's job. Note that SDL_GetError() is not cleared on success, so call SDLError::SDLClearError() first if you intend to read it.

Surprises worth reading about

ext-sdl3's array returns are not uniformly shaped — SDLGetWindowSize gives a list, SDLGetRenderDrawColor a keyed map, and SDLCreateTexture the whole struct with the handle under a ptr key. SDLRenderClear returns void where SDL returns bool. These are mirrored, not corrected. See .okf/quirks.md.

Verify

php scripts/generate.php --check              # GEN_OK, written=0 stale=0
node scripts/gates/verify-generate.mjs        # GEN_OK
node scripts/gates/verify-parity.mjs          # PARITY_OK        716 = 716
node scripts/gates/verify-style.mjs           # STYLE_OK         68 files
node scripts/gates/verify-enum-values.mjs     # ENUM_VALUES_OK   836 cases vs cc
node scripts/gates/verify-ext-control.mjs     # EXT_CONTROL_CONSISTENT
vendor/bin/pest                               # 24 passed
php examples/proof_window_typed.php           # PROOF_WINDOW_TYPED_OK

The proof opens a small window, presents four frames, and byte-checks 76,800 pixels read back through SDL_RenderReadPixels against the colour each frame was cleared to. All four match exactly.

Regenerating

Everything under src/ is generated. Do not hand-edit it — change scripts/Generator/** and re-run php scripts/generate.php. The generator reads the installed extension by Reflection, so ext-sdl3 must be loaded; it exits with a message rather than emitting a partial surface. SDL3 headers are found at /opt/homebrew/include/SDL3 or wherever JOVIAN_SDL3_HEADERS points.

Not included

sdl3image and sdl3ttf are separate extensions and want separate packages.

Further reading

Agent and contributor guidance is in AGENTS.md; the knowledge bundle is at .okf/, starting with .okf/index.md.

Licence

MIT.