$ SwiftOpenUI Core (platform-independent) | +-- BackendGTK4 (Linux) -> GTK4 native widgets +-- BackendWin32 (Windows) -> HWND + Direct2D rendering
SwiftOpenUI Core (platform-independent) | +-- BackendGTK4 (Linux) -> GTK4 native widgets +-- BackendWin32 (Windows) -> HWND + Direct2D rendering
SwiftOpenUI Core (platform-independent) | +-- BackendGTK4 (Linux) -> GTK4 native widgets +-- BackendWin32 (Windows) -> HWND + Direct2D rendering
struct SettingsRow: View { let label: String let value: String var body: some View { HStack { Text(label) Spacer() Text(value) .foregroundColor(.gray) .lineLimit(1) } .padding(.horizontal, 16) .padding(.vertical, 10) }
}
struct SettingsRow: View { let label: String let value: String var body: some View { HStack { Text(label) Spacer() Text(value) .foregroundColor(.gray) .lineLimit(1) } .padding(.horizontal, 16) .padding(.vertical, 10) }
}
struct SettingsRow: View { let label: String let value: String var body: some View { HStack { Text(label) Spacer() Text(value) .foregroundColor(.gray) .lineLimit(1) } .padding(.horizontal, 16) .padding(.vertical, 10) }
}
xcode-select ---weight: 500;">install
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
xcode-select ---weight: 500;">install
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
xcode-select ---weight: 500;">install
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
# Install Swift via swiftly (official Swift version manager)
-weight: 500;">curl -L https://swiftlang.github.io/swiftly/swiftly--weight: 500;">install.sh | bash
source ~/.swiftly/env.sh # Install GTK4 development libraries
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install libgtk-4-dev # Ubuntu / Debian
# -weight: 600;">sudo -weight: 500;">dnf -weight: 500;">install gtk4-devel # Fedora # Clone and run
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
# Install Swift via swiftly (official Swift version manager)
-weight: 500;">curl -L https://swiftlang.github.io/swiftly/swiftly--weight: 500;">install.sh | bash
source ~/.swiftly/env.sh # Install GTK4 development libraries
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install libgtk-4-dev # Ubuntu / Debian
# -weight: 600;">sudo -weight: 500;">dnf -weight: 500;">install gtk4-devel # Fedora # Clone and run
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
# Install Swift via swiftly (official Swift version manager)
-weight: 500;">curl -L https://swiftlang.github.io/swiftly/swiftly--weight: 500;">install.sh | bash
source ~/.swiftly/env.sh # Install GTK4 development libraries
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">install libgtk-4-dev # Ubuntu / Debian
# -weight: 600;">sudo -weight: 500;">dnf -weight: 500;">install gtk4-devel # Fedora # Clone and run
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
-weight: 500;">git clone https://github.com/codelynx/SwiftOpenUI.-weight: 500;">git
cd SwiftOpenUI
swift run HelloWorld
#if os(macOS)
import SwiftUI
import MacExampleSupport
#else
import SwiftOpenUI
#if canImport(BackendGTK4)
import BackendGTK4
#endif
#if canImport(BackendWin32)
import BackendWin32
#endif
#endif struct HelloWorldApp: App { var body: some Scene { WindowGroup("Hello World") { Text("Hello, SwiftOpenUI!") .padding() } }
} #if os(macOS)
MacAppLauncher.run(HelloWorldApp.self)
#elseif canImport(BackendGTK4)
GTK4Backend().run(HelloWorldApp.self)
#elseif canImport(BackendWin32)
Win32Backend().run(HelloWorldApp.self)
#endif
#if os(macOS)
import SwiftUI
import MacExampleSupport
#else
import SwiftOpenUI
#if canImport(BackendGTK4)
import BackendGTK4
#endif
#if canImport(BackendWin32)
import BackendWin32
#endif
#endif struct HelloWorldApp: App { var body: some Scene { WindowGroup("Hello World") { Text("Hello, SwiftOpenUI!") .padding() } }
} #if os(macOS)
MacAppLauncher.run(HelloWorldApp.self)
#elseif canImport(BackendGTK4)
GTK4Backend().run(HelloWorldApp.self)
#elseif canImport(BackendWin32)
Win32Backend().run(HelloWorldApp.self)
#endif
#if os(macOS)
import SwiftUI
import MacExampleSupport
#else
import SwiftOpenUI
#if canImport(BackendGTK4)
import BackendGTK4
#endif
#if canImport(BackendWin32)
import BackendWin32
#endif
#endif struct HelloWorldApp: App { var body: some Scene { WindowGroup("Hello World") { Text("Hello, SwiftOpenUI!") .padding() } }
} #if os(macOS)
MacAppLauncher.run(HelloWorldApp.self)
#elseif canImport(BackendGTK4)
GTK4Backend().run(HelloWorldApp.self)
#elseif canImport(BackendWin32)
Win32Backend().run(HelloWorldApp.self)
#endif
VStack(alignment: .leading, spacing: 0) { Text("GENERAL") .font(.caption) .foregroundColor(.gray) .padding(.horizontal, 16) .padding(.vertical, 8) settingsRow("Username", value: "kaz.yoshikawa") settingsDivider() settingsRow("Email", value: "[email protected]") settingsDivider() settingsRow("Language", value: "English")
} func settingsRow(_ label: String, value: String) -> some View { HStack { Text(label) Spacer() Text(value) .foregroundColor(.gray) .lineLimit(1) } .padding(.horizontal, 16) .padding(.vertical, 10)
}
VStack(alignment: .leading, spacing: 0) { Text("GENERAL") .font(.caption) .foregroundColor(.gray) .padding(.horizontal, 16) .padding(.vertical, 8) settingsRow("Username", value: "kaz.yoshikawa") settingsDivider() settingsRow("Email", value: "[email protected]") settingsDivider() settingsRow("Language", value: "English")
} func settingsRow(_ label: String, value: String) -> some View { HStack { Text(label) Spacer() Text(value) .foregroundColor(.gray) .lineLimit(1) } .padding(.horizontal, 16) .padding(.vertical, 10)
}
VStack(alignment: .leading, spacing: 0) { Text("GENERAL") .font(.caption) .foregroundColor(.gray) .padding(.horizontal, 16) .padding(.vertical, 8) settingsRow("Username", value: "kaz.yoshikawa") settingsDivider() settingsRow("Email", value: "[email protected]") settingsDivider() settingsRow("Language", value: "English")
} func settingsRow(_ label: String, value: String) -> some View { HStack { Text(label) Spacer() Text(value) .foregroundColor(.gray) .lineLimit(1) } .padding(.horizontal, 16) .padding(.vertical, 10)
}
HStack(spacing: 12) { card(title: "CPU", value: "45%", color: .orange) card(title: "Memory", value: "2.1 GB", color: .red) card(title: "Disk", value: "128 GB", color: .purple)
} func card(title: String, value: String, color: Color) -> some View { VStack(alignment: .leading, spacing: 8) { Text(title).font(.caption).foregroundColor(.gray) Text(value).font(.title).foregroundColor(color) } .frame(maxWidth: .infinity, alignment: .leading) .padding(12) .background(Color(red: 0.15, green: 0.15, blue: 0.15))
}
HStack(spacing: 12) { card(title: "CPU", value: "45%", color: .orange) card(title: "Memory", value: "2.1 GB", color: .red) card(title: "Disk", value: "128 GB", color: .purple)
} func card(title: String, value: String, color: Color) -> some View { VStack(alignment: .leading, spacing: 8) { Text(title).font(.caption).foregroundColor(.gray) Text(value).font(.title).foregroundColor(color) } .frame(maxWidth: .infinity, alignment: .leading) .padding(12) .background(Color(red: 0.15, green: 0.15, blue: 0.15))
}
HStack(spacing: 12) { card(title: "CPU", value: "45%", color: .orange) card(title: "Memory", value: "2.1 GB", color: .red) card(title: "Disk", value: "128 GB", color: .purple)
} func card(title: String, value: String, color: Color) -> some View { VStack(alignment: .leading, spacing: 8) { Text(title).font(.caption).foregroundColor(.gray) Text(value).font(.title).foregroundColor(color) } .frame(maxWidth: .infinity, alignment: .leading) .padding(12) .background(Color(red: 0.15, green: 0.15, blue: 0.15))
}
HStack(spacing: 0) { VStack(alignment: .leading, spacing: 0) { sidebarItem("Inbox", count: "12", selected: true) sidebarItem("Sent", count: "3", selected: false) sidebarItem("Drafts", count: "1", selected: false) sidebarItem("Archive", count: "847", selected: false) Spacer() } .frame(width: 140) Color.gray.frame(width: 1) // divider VStack(alignment: .leading, spacing: 12) { // detail content } .frame(maxWidth: .infinity, alignment: .leading) .padding(16)
}
.frame(height: 250)
HStack(spacing: 0) { VStack(alignment: .leading, spacing: 0) { sidebarItem("Inbox", count: "12", selected: true) sidebarItem("Sent", count: "3", selected: false) sidebarItem("Drafts", count: "1", selected: false) sidebarItem("Archive", count: "847", selected: false) Spacer() } .frame(width: 140) Color.gray.frame(width: 1) // divider VStack(alignment: .leading, spacing: 12) { // detail content } .frame(maxWidth: .infinity, alignment: .leading) .padding(16)
}
.frame(height: 250)
HStack(spacing: 0) { VStack(alignment: .leading, spacing: 0) { sidebarItem("Inbox", count: "12", selected: true) sidebarItem("Sent", count: "3", selected: false) sidebarItem("Drafts", count: "1", selected: false) sidebarItem("Archive", count: "847", selected: false) Spacer() } .frame(width: 140) Color.gray.frame(width: 1) // divider VStack(alignment: .leading, spacing: 12) { // detail content } .frame(maxWidth: .infinity, alignment: .leading) .padding(16)
}
.frame(height: 250)
HStack(spacing: 0) { HStack(spacing: 6) { Color.green.frame(width: 8, height: 8) Text("Connected").font(.caption).foregroundColor(.gray) } .padding(.horizontal, 12) Color.gray.frame(width: 1, height: 16) // divider Text("3 files synced") .font(.caption) .foregroundColor(.gray) .frame(maxWidth: .infinity) // fills center Color.gray.frame(width: 1, height: 16) // divider HStack(spacing: 12) { Text("45%").font(.caption).foregroundColor(.gray) Text("2.1 MB/s").font(.caption).foregroundColor(.gray) } .padding(.horizontal, 12)
}
.frame(height: 28)
HStack(spacing: 0) { HStack(spacing: 6) { Color.green.frame(width: 8, height: 8) Text("Connected").font(.caption).foregroundColor(.gray) } .padding(.horizontal, 12) Color.gray.frame(width: 1, height: 16) // divider Text("3 files synced") .font(.caption) .foregroundColor(.gray) .frame(maxWidth: .infinity) // fills center Color.gray.frame(width: 1, height: 16) // divider HStack(spacing: 12) { Text("45%").font(.caption).foregroundColor(.gray) Text("2.1 MB/s").font(.caption).foregroundColor(.gray) } .padding(.horizontal, 12)
}
.frame(height: 28)
HStack(spacing: 0) { HStack(spacing: 6) { Color.green.frame(width: 8, height: 8) Text("Connected").font(.caption).foregroundColor(.gray) } .padding(.horizontal, 12) Color.gray.frame(width: 1, height: 16) // divider Text("3 files synced") .font(.caption) .foregroundColor(.gray) .frame(maxWidth: .infinity) // fills center Color.gray.frame(width: 1, height: 16) // divider HStack(spacing: 12) { Text("45%").font(.caption).foregroundColor(.gray) Text("2.1 MB/s").font(.caption).foregroundColor(.gray) } .padding(.horizontal, 12)
}
.frame(height: 28)
# Showcase
swift run HelloWorld # Minimal app
swift run Stopwatch # Timer with -weight: 500;">start/-weight: 500;">stop/lap
swift run ColorMixer # Color picker with sliders and harmony
swift run Calculator # Grid-based calculator
swift run SimplePaint # Drawing app with tools and undo
swift run LayoutStress # Advanced layout composition stress test # Parity (one per feature category)
swift run ParityViewsBasic
swift run ParityViewsLayout
swift run ParityModifiers
swift run ParityStateData
swift run ParityNavigation
swift run ParityEnvironment
swift run ParityGestures
swift run ParityAnimation
swift run ParityFocus
swift run ParityAppStructure
swift run ParityViewsContainers
# Showcase
swift run HelloWorld # Minimal app
swift run Stopwatch # Timer with -weight: 500;">start/-weight: 500;">stop/lap
swift run ColorMixer # Color picker with sliders and harmony
swift run Calculator # Grid-based calculator
swift run SimplePaint # Drawing app with tools and undo
swift run LayoutStress # Advanced layout composition stress test # Parity (one per feature category)
swift run ParityViewsBasic
swift run ParityViewsLayout
swift run ParityModifiers
swift run ParityStateData
swift run ParityNavigation
swift run ParityEnvironment
swift run ParityGestures
swift run ParityAnimation
swift run ParityFocus
swift run ParityAppStructure
swift run ParityViewsContainers
# Showcase
swift run HelloWorld # Minimal app
swift run Stopwatch # Timer with -weight: 500;">start/-weight: 500;">stop/lap
swift run ColorMixer # Color picker with sliders and harmony
swift run Calculator # Grid-based calculator
swift run SimplePaint # Drawing app with tools and undo
swift run LayoutStress # Advanced layout composition stress test # Parity (one per feature category)
swift run ParityViewsBasic
swift run ParityViewsLayout
swift run ParityModifiers
swift run ParityStateData
swift run ParityNavigation
swift run ParityEnvironment
swift run ParityGestures
swift run ParityAnimation
swift run ParityFocus
swift run ParityAppStructure
swift run ParityViewsContainers - Swift developers who want to ship tools on Linux — server admin panels, developer utilities, data viewers
- Swift developers who want to ship on Windows — internal tools, build monitors, configuration editors
- Teams with existing SwiftUI code who want to bring it cross-platform without a rewrite
- Developers who like Swift's type safety and declarative UI but need to target non-Apple platforms - Download and -weight: 500;">install the Swift toolchain for Windows (includes the compiler and SPM)
- Install Visual Studio Build Tools with the C++ Desktop Development workload (needed for the linker and Windows SDK headers)
- Open a Developer Command Prompt or Developer PowerShell - #if os(macOS) imports real SwiftUI — your parity check
- #else imports SwiftOpenUI with whichever backend is available
- The view code (HelloWorldApp, WindowGroup, Text) is identical across all three
- Only the entry point differs — one line per platform - macOS captures the reference. Each test scenario renders a real SwiftUI view, walks the view tree, and saves the positions and sizes as a JSON fixture.
- Each platform renders the same view. GTK4 captures GTK widget positions. Win32 captures HWND positions. Same JSON format.
- Automated comparison. A shared comparison engine matches leaf nodes (the actual visible content), normalizes coordinates, and reports differences. Structural layout bugs (wrong position, wrong spacing) fail the test. Font-metric differences (expected — different fonts on each platform) are reported as informational.
- 50 test scenarios covering stacks, frames, padding, spacers, alignment, and the composition patterns that real apps use. - Adaptive default spacing — macOS SwiftUI uses 0pt between adjacent Text views; SwiftOpenUI currently uses 8pt. Fixing this closes most remaining Win32 layout residuals.
- Layout priority-based flex distribution — SwiftUI's priority-based algorithm for dividing space among flexible children.
- Continued parity testing — expanding the 50-scenario suite as new views and modifiers are added. - GitHub: github.com/codelynx/SwiftOpenUI
- Getting Started: docs/guides/getting-started.md
- Feature Parity Matrix: docs/architecture/swiftui-parity-matrix.md