A modern, cross-platform windowing library for Swift, built from the ground up with Swift 6 concurrency in mind.
Lumina provides a clean, type-safe API for creating windows and handling user input across macOS and Windows. It leverages Swift's latest features including strict concurrency, ownership annotations, and protocol-oriented design.
Current Status: Milestone 0 (Wave A) - Core Windowing & Input
- Cross-platform: macOS (AppKit) and Windows (Win32 API) backends
- Modern Swift: Built with Swift 6.2+, strict concurrency, and borrowing ownership model
- Type-safe: Explicit error handling with Result types
- DPI-aware: Automatic logical/physical coordinate conversion
- Async-friendly: Works seamlessly with Swift's async/await concurrency
- macOS: macOS 15.0+ (Sequoia)
- Windows: Windows 11+ (planned)
- Swift: 6.0+
- Xcode: 16.0+ (for macOS development)
Add Lumina to your Package.swift:
dependencies: [
.package(url: "https://github.com/yourusername/Lumina.git", from: "0.1.0")
]Then add it to your target dependencies:
.target(
name: "YourApp",
dependencies: ["Lumina"]
)The simplest Lumina application creates a window and runs the event loop:
import Lumina
@MainActor
func main() async throws {
// Create application
var app = try Application()
// Create window
let window = try Window.create(
title: "Hello, Lumina!",
size: LogicalSize(width: 800, height: 600)
).get()
window.show()
// Run event loop
try app.run()
}
try await main()Lumina provides comprehensive window control:
var window = try Window.create(
title: "My App",
size: LogicalSize(width: 1024, height: 768),
resizable: true
).get()
// Show/hide window
window.show()
window.hide()
// Move and resize
window.moveTo(LogicalPosition(x: 100, y: 100))
window.resize(LogicalSize(width: 1280, height: 720))
// Set constraints
window.setMinSize(LogicalSize(width: 640, height: 480))
window.setMaxSize(LogicalSize(width: 1920, height: 1080))
// Focus
window.requestFocus()
// Query state
let size = window.size()
let position = window.position()
let scaleFactor = window.scaleFactor()
// Close (consumes window)
window.close()Lumina automatically handles DPI scaling across different displays:
let window = try Window.create(
title: "Scaling Demo",
size: LogicalSize(width: 800, height: 600)
).get()
// Query scale factor
let scaleFactor = window.scaleFactor() // 1.0 = normal, 2.0 = Retina
// Convert between logical and physical coordinates
let logicalSize = LogicalSize(width: 800, height: 600)
let physicalSize = logicalSize.toPhysical(scaleFactor: scaleFactor)
print("Logical: \(logicalSize.width) × \(logicalSize.height) points")
print("Physical: \(physicalSize.width) × \(physicalSize.height) pixels")Lumina supports different event loop patterns:
var app = try Application()
let window = try Window.create(
title: "App",
size: LogicalSize(width: 800, height: 600)
).get()
window.show()
// Blocks until quit() is called
try app.run()var app = try Application()
let window = try Window.create(
title: "Game",
size: LogicalSize(width: 1920, height: 1080)
).get()
window.show()
// Custom game loop
while !shouldQuit {
// Process all pending events
_ = try app.poll()
// Update game state
updateGame(deltaTime)
// Render frame
renderFrame()
}var app = try Application()
let window = try Window.create(
title: "Editor",
size: LogicalSize(width: 1024, height: 768)
).get()
window.show()
// Efficient idle loop
while !shouldQuit {
try app.wait() // Sleep until event arrives
_ = try app.poll() // Process the event
}Change cursor appearance and visibility:
import Lumina
// Change cursor
Cursor.set(.hand) // Pointing hand
Cursor.set(.ibeam) // Text cursor
Cursor.set(.crosshair) // Crosshair
Cursor.set(.resizeNS) // Vertical resize
// Hide/show cursor
Cursor.hide()
Cursor.show()
// Reset to default
Cursor.set(.arrow)Lumina works seamlessly with Swift concurrency:
@MainActor
func main() async throws {
var app = try Application()
let window = try Window.create(
title: "Async Demo",
size: LogicalSize(width: 800, height: 600)
).get()
window.show()
// Background task can post user events
Task.detached {
let result = await performNetworkRequest()
await app.postUserEvent(UserEvent(result))
}
// Event loop processes user events
try app.run()
}The Examples/ directory contains complete example applications:
- HelloWindow: Minimal window creation
- InputExplorer: Input event handling with async/await validation
- ScalingDemo: DPI scaling and coordinate conversion
Build and run examples:
cd Examples/HelloWindow
swift run
cd ../InputExplorer
swift run
cd ../ScalingDemo
swift runApplication: Event loop and application lifecycle managementWindow: Window creation and manipulationCursor: Cursor appearance and visibility control
LogicalSize/PhysicalSize: Size in points vs pixelsLogicalPosition/PhysicalPosition: Position in points vs pixels
Event: Window, pointer, keyboard, and user eventsWindowEvent: Created, closed, resized, moved, focused, scale changedPointerEvent: Moved, entered, left, button pressed/released, wheelKeyboardEvent: Key down/up, text inputUserEvent: Custom application events
Note: Event callback API will be added in a future milestone
LuminaError: Typed error enum with cases:windowCreationFailed(reason:)platformError(code:message:)invalidState(_:)eventLoopFailed(reason:)
Lumina uses a layered architecture:
- Public API Layer (
Lumina): Cross-platform types and APIs - Backend Layer: Platform-specific implementations
- macOS: AppKit/Cocoa (NSApplication, NSWindow)
- Windows: Win32 API (CreateWindowEx, message loop)
- Foundation Layer: Shared geometry, events, errors
All platform-specific code is conditionally compiled, resulting in zero overhead on each platform.
Lumina uses Swift Testing framework:
# Run all tests
swift test
# Run with parallel execution
swift test --parallel
# Run specific test suite
swift test --filter GeometryTests- ✅ Window creation and management
- ✅ Basic event loop (run, poll, wait)
- ✅ DPI/scaling support
- ✅ Cursor control
- ⏳ Event callbacks (future enhancement)
- Wave B: Graphics integration (Metal/DirectX)
- Wave C: Advanced input (gamepad, touch)
- Wave D: Window features (menus, dialogs, file pickers)
- Wave E: Platform extensions (notifications, system tray)
See CONTRIBUTING.md for development guidelines.
Licensed under the MIT License. See LICENSE for details.
Lumina is inspired by modern windowing libraries like winit (Rust) and GLFW, reimagined for Swift's unique capabilities.