SwiftSDL
SDL3 in Swift
Install / Use
/learn @KevinVitale/SwiftSDLREADME
SwiftSDL — Cross-Platform Targets with Swift & SDL3
SwiftSDL is an open-source Swift library that provides a complete interface for working with the C-based SDL (Simple DirectMedia Layer) library. This wrapper allows developers to leverage SDL's cross-platform multimedia and game development capabilities in Swift applications across macOS, iOS, and Linux.
<img src="https://www.libsdl.org/media/SDL_logo.png" height="20" max-width="90%" alt="SDL2" /> Simple DirectMedia Layer 3.0
"Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL/Direct3D/Metal/Vulkan. It is used by video playback software, emulators, and popular games including Valve's award winning catalog and many Humble Bundle games." - wiki.libsdl.org
🏁 Getting Started
📋 Requirements
- Swift 6.0.2, or later; and,
- SDL v3.1.6-preview, (required only for Linux).
🔧 Installation
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MySDLGame",
platforms: [
.macOS(.v13)
],
dependencies: [
.package(url: "https://github.com/KevinVitale/SwiftSDL.git", from: "0.2.0-alpha.16"),),
],
targets: [
.executableTarget(
name: "SwiftSDLTest",
dependencies: [
"SwiftSDL"
],
resources: [
.process("../Resources/BMP"),
]
),
]
)
👀 Overview
Like Swift itself, SwiftSDL makes SDL3 approachable for newcomers and powerful for experts.
👾 Introduction
A complete SwiftSDL game consists of the following 22-lines of code:
import SwiftSDL
@main
final class MyGame: Game {
private enum CodingKeys: String, CodingKey {
case options
}
@OptionGroup
var options: GameOptions
func onReady(window: any Window) throws(SDL_Error) {
/* create a renderer, or acquire a gpu device. */
/* load assets or resources. */
}
func onUpdate(window: any Window) throws(SDL_Error) {
/* handle game logic and render frames */
}
func onEvent(window: any Window, _ event: SDL_Event) throws(SDL_Error) {
/* respond to events */
}
func onShutdown(window: (any Window)?) throws(SDL_Error) {
/* release objects and unload resources */
}
}
The class, MyGame, conforms to the Game protocol. A window is created automatically using reasonable defaults, although, it's possible to override the window's creation manually.
Underneath the hood, the Game protocol has implemented SDL3's new main callbacks.
GameOptions are runtime arguments which alter the behavior or your application, such as your window's appearance.
🧩 Tutorial
Let's create an app using SwiftSDL from start-to-finish.
Step 1: Create the project
Using Swift's command-line utility, we'll create the project in an empty directory
# Create an empty directory for our project
mkdir MyGame
cd MyGame
# Create the executable package
swift package init --type executable
Step 2: Add SwiftSDL
Update the Package.swift file to include SwiftSDL as a dependency:
Note: you may need adjust
platformsto use.macOS(.v13).
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyGame",
platforms: [
.macOS(.v13)
],
dependencies: [
.package(url: "https://github.com/KevinVitale/SwiftSDL.git", from: "0.2.0-alpha.17")
],
targets: [
// Targets can depend on other targets in this package and products from dependencies.
.executableTarget(
name: "MyGame",
dependencies: [
"SwiftSDL"
]
),
]
)
Step 3: Create the game
Rename main.swift to MyGame.swift:
mv Sources/main.swift Sources/MyGame.swift
Then replace MyGame.swift with the following code:
import SwiftSDL
@main
final class MyGame: Game {
private enum CodingKeys: String, CodingKey {
case options, message
}
@OptionGroup
var options: GameOptions
@Argument
var message: String = "Hello, SwiftSDL!"
private var renderer: (any Renderer)! = nil
func onReady(window: any Window) throws(SDL_Error) {
renderer = try window.createRenderer()
}
func onUpdate(window: any Window) throws(SDL_Error) {
try renderer
.clear(color: .gray)
.debug(text: message, position: [12, 12], scale: [2, 2])
.fill(rects: [24, 48, 128, 128], color: .white)
.fill(rects: [36, 60, 104, 104], color: .green)
.present()
}
func onEvent(window: any Window, _ event: SDL_Event) throws(SDL_Error) {
}
func onShutdown(window: (any Window)?) throws(SDL_Error) {
renderer = nil
}
}
Then start the game:
swift run
Note: You should see a window with a gray background, a message saying "Hello, SwiftSDL!", and two squares: one large white one, and a smaller green one.
Your game has several options built-in. To see them all, use --help:
swift run MyGame --help
USAGE: my-game [<options>] [<message>]
ARGUMENTS:
<message> (default: Hello, SwiftSDL!)
OPTIONS:
--hide-cursor Hide the system's cursor
--auto-scale-content Stretch the content to fill the window
--logical-size <logical-size>
Forces the rendered content to be a certain logical size (WxH)
--logical-presentation <logical-presentation>
Forces the rendered content to be a certain logical order; overrides '--auto-scale-content' (values: disabled,
stretch, letterbox, overscan, integer-scale; default: disabled)
--vsync-rate <vsync-rate>
Set vertical synchronization rate (values: adaptive, disabled, interger value; default: disabled)
--window-always-on-top Window is always kept on top
--window-fullscreen Window is set to fullscreen
--window-transparent Window is uses a transparent buffer
--window-maximized Create a maximized window; requires '--window-resizable'
--window-minimized Create a minimized window
--window-max-size <window-max-size>
Specify the maximum window's size (WxH)
--window-min-size <window-min-size>
Specify the minimum window's size (WxH)
--window-mouse-focus Force the window to have mouse focus
--window-no-frame Create a borderless window
--window-resizable Enable window resizability
--window-position <window-position>
Specify the window's position (XxY)
--window-size <window-size>
Specify the window's size (WxH)
--window-title <window-title>
Specify the window's title
-h, --help Show help information.
Step 4: Sample Apps
SwiftSDL includes several samples to help you get started.
Test Bench
These are reimplementations of a variety of SDL3's tests using SwiftSDL:
| Build Command | Image Preview |
|-|-|
| swift run sdl test audio-info | <img width="240" alt="test-controller" src="https://github.com/user-attachments/assets/cd9574ca-92a2-4a4c-8bad-eeee9593bbb6"/> |
| swift run sdl test controller | <img width="480" alt="test-controller" src="https://github.com/user-attachments/assets/c67d6e8b-3a25-48d6-b195-b501ae536f4f"/> |
| swift run sdl test camera | <img width="480" alt="test-camera" src="https://github.com/user-attachments/assets/e817a454-970b-4b63-ba74-3541b951f532"/> |
| swift run sdl test geometry | <img width="480" alt="test-geometry" src="https://github.com/user-attachments/assets/13a9af58-6668-48a0-9cca-70b76472a569"/> |
| swift run sdl test mouse-grid | <img width="480" alt="mouse-grid" src="https://github.com/user-attachments/assets/28902a4c-6fb1-4c08-aa9c-d1047831fb41"/> |
| swift run sdl test sprite | <img width="480" alt="test-sprite" src="https://github.com/user-attachments/assets/9e1b8c5e-d4bd-471c-9d61-a3337442981f"/> |
| swift run sdl test gpu-examples | <img width="480" alt="test-sprite" src="https://github.com/user-attachments/assets/082778b6-3f9e-4612-b187-930af3e7d74f"/> |
Games
| Build Command | Image Preview |
|-|-|
| swift run sdl games flappy-bird | <img width="480" alt="game-flappy-bird" src="https://github.com/user-attachments/assets/2817f22c-8557-4871-bfb8-b2bf496ffb77"> |
| swift run sdl games stinky-duck | <img width="480" alt="game-flappy-bird" src="https://github.com/user-attachments/assets/afad73dd-bbd7-48f4-b6fd-144d61172968"> |
Xcode Project: macOS, iOS, tvOS
Explore: Samples/SwiftSDL-Xcode
💻 Platform-Specific Instructions
SwiftSDL doesn't work without SDL3. Refer to the fo
Related Skills
node-connect
343.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
92.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
343.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
343.3kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
