Cross-platform SwiftUI framework — write SwiftUI, run anywhere.
Sources/SwiftOpenUI/— Core platform-independent library (Views, State, Layout, Modifiers, Environment, Backend protocol)Sources/Backend/GTK4/— Linux backend (GTK4): CGTK system module, CGTKBridge interop, RenderingSources/Backend/Win32/— Windows backend (Win32): CWin32, CWin32Bridge, Rendering + LayoutEngineSources/Backend/Web/— Web/Wasm backend (experimental): DOM rendering via JavaScriptKitExamples/Showcase/— Polished demo apps (HelloWorld, Stopwatch, ColorMixer, Calculator, SimplePaint, LayoutStress)Examples/Parity/— Matrix-backed coverage examples (11 parity targets)Tests/SwiftOpenUITests/— Core tests (platform-independent)Tests/BackendTests/— Platform-specific backend testsdocs/— Architecture, API reference, porting guides, missionconfigure— Setup script: installs swiftly, open-source Swift toolchain, Wasm SDK
main— clean until v1.0, do not merge to main without explicit instructiondevelop— active development, all work happens hereexperimental/*— experimental features (e.g.experimental/web-wasm-poc)
- Coordinator creates one pushed core/base branch per batch and declares the exact base commit hash.
- After pushing a core/base branch, coordinator must verify the remote ref explicitly with:
git ls-remote --heads origin <branch>- only send handoff after the remote hash matches the intended local commit
- Every platform handoff must include:
- branch
- commit
- base commit
- changed files
- tests run
- Worker first step must be:
git fetch origingit switch -C <worker-branch> origin/<base-branch>git rev-parse HEAD
- If the worker sees a different commit hash than the handoff hash, stop and report a stale base immediately.
- Platform branches may edit only backend-owned files and backend tests.
- Platform branches must not update shared truth docs:
docs/api/implementation-tracker/**docs/architecture/swiftui-parity-matrix.md- repo status docs such as
CLAUDE.md
- Once any platform branch from a batch is merged into
develop, sibling platform branches are stale by default. - After that point, further platform work must be:
- rebased onto current
develop, or - delivered as focused cherry-pickable commits
- rebased onto current
- Use this decision rule:
batch/*branch: created from the coordinator’s batch base, intended for one mergefix/*branch: created from currentdevelop, intended for quick merge or cherry-pick
- Coordinator owns:
- core API design
- merge conflict resolution
- tracker regeneration
- parity/doc truth
- If a platform report arrives after the batch is already integrated, coordinator should prefer cherry-picking the focused fix commit instead of merging the stale platform branch head.
Several agent sessions may run against this repo at once, sharing one working
directory. Before switching branches, modifying files, or running builds, read
AGENTS.md → "Concurrent Sessions". Use the main checkout only when ownership is
explicitly established; otherwise create a separate worktree with its own build
directory.
# macOS (uses real SwiftUI for examples)
swift build
swift test # ~628 macOS / ~707 Linux
# WebAssembly (requires open-source Swift 6.2.4 via swiftly, not Xcode's)
# Build per product: a blanket Wasm build fails linking the BackendAndroid dynamic library.
# On Xcode 27, prefix with DEVELOPER_DIR=<Xcode 26.x>/Contents/Developer (see docs/guides/web-setup.md).
swiftly run swift build --swift-sdk swift-6.2.4-RELEASE_wasm --product HelloWorld +6.2.4
# Run examples on macOS
swift run HelloWorld
swift run Stopwatch
swift run ColorMixer
swift run SimplePaint
swift run LayoutStress
swift run ParityViewsBasic
# Run in browser (Wasm) — builds all examples into web/examples, then serves them
./web/build-wasm.sh
cd web && npx vite # http://localhost:3000
# Package an app as a .app bundle
swift package create-bundle HelloWorld --allow-writing-to-package-directory
# Output: .build/bundles/HelloWorld.app
# Full setup from scratch (macOS only)
./configure- Core is platform-independent:
Sources/SwiftOpenUI/has zero platform imports. All GTK/Win32/Web code lives inSources/Backend/. - Protocol-based rendering: Backends extend core views with
GTKRenderable/WebRenderable/ etc. The renderer checksif let renderable = view as? Renderablebefore falling back to body recursion. - On macOS, examples use real SwiftUI:
#if os(macOS) import SwiftUI— validates API compatibility. - Manifest conditionals check HOST, not target:
#if os()and#if arch()in Package.swift evaluate the build machine. Example deps always include SwiftOpenUI. Web backend + JavaScriptKit are gated to#if os(macOS)(Wasm cross-compilation always happens from macOS). GTK4 and Win32 backends are gated to their native OS. - Namespace conflicts: On macOS,
ObservableObjectandPublishedclash with Combine. Tests qualify asSwiftOpenUI.ObservableObjectand@SwiftOpenUI.Published. Seedocs/issues/observable-namespace-conflict.md. - State management (@State, @Binding, @ObservedObject, @Published, @StateObject, @EnvironmentObject, @FocusState, @Observable) is fully platform-independent with thread-safe storage.
- Environment TLS: pthread on Linux/macOS, TlsAlloc on Windows, simple global on Wasm (single-threaded).
- Scene rendering is recursive:
renderScenewalksScene.bodyuntil it hits a terminalWindowGrouporWindow. - App bundle dev mode: When running via
swift run,AppBundle.mainwalks up from the executable looking forPackage.swift+Resources/. Place resources inResources/at the package root for development-time resource lookup without a.appbundle.
┌─────────────────────────────────────────────────────┐
│ Examples (import SwiftUI on macOS, SwiftOpenUI else)│
├─────────────────────────────────────────────────────┤
│ SwiftOpenUI Core │
│ View, State, Layout, Modifiers, Environment │
├──────────────┬───────────────┬──────────────────────┤
│ BackendGTK4 │ BackendWin32 │ BackendWeb │
│ GTKRenderer │ WinRenderer │ WebRenderer │
│ GTKViewHost │ Win32ViewHost│ WebViewHost │
├──────────────┼───────────────┼──────────────────────┤
│ CGTK │ CWin32 │ JavaScriptKit │
│ CGTKBridge │ CWin32Bridge │ (DOM API) │
└──────────────┴───────────────┴──────────────────────┘
Text, Button, TextField, SecureField, TextEditor, Toggle, Slider, Stepper, Picker, DatePicker, ProgressView, Label, Link, ScrollView, List, Image, VStack, HStack, ZStack, Spacer, Divider, Color, Group, ForEach, AnyView, EmptyView, TabView, Grid, GridRow, Form, Section, DisclosureGroup, OutlineGroup, LazyVStack, LazyHStack, LazyVGrid, LazyHGrid, Menu, Canvas, GeometryReader, ViewThatFits, NavigationSplitView, ConfirmationDialog, Path (with StrokeStyle, Shading), Circle, Rectangle, RoundedRectangle, Capsule, Ellipse (Shape protocol with .fill()/.stroke()), ScrollViewReader, LinearGradient, RadialGradient
WindowGroup, Window (GTK/Win32: functional with OpenWindowAction; Web: core type only), Commands (CommandGroup, CommandMenuItem — GTK/Win32: native menu bar with observation-driven enable/disable; Web: not yet)
NavigationStack, NavigationLink, NavigationSplitView, NavigationPath, .navigationTitle(), .navigationDestination(for:), NavigateAction (environment)
.padding(), .frame(), .foregroundColor(), .foregroundStyle(), .background(), .font(), .border(), .opacity(), .offset(), .scaleEffect(), .animation(), .imageScale(), .onTapGesture(), .onLongPressGesture(), .onDrag(), .disabled(), .environmentObject(), .environment(), withAnimation(), .cornerRadius(), .shadow(), .rotationEffect(), .overlay(), .sheet(), .alert(), .confirmationDialog(), .onAppear(), .onDisappear(), .searchable(), .toolbar(), .gridCellColumns(), .pickerStyle(), .navigationSplitViewColumnWidth(), .ignoresSafeArea(), .safeAreaInset(), .lineLimit(), .truncationMode(), .lineSpacing(), .multilineTextAlignment(), .clipShape(), .clipped(), .hidden(), .blur(), .buttonStyle(), .toggleStyle(), .textFieldStyle(), .onChange(), .contextMenu(), .position(), .layoutPriority(), .fixedSize(), .popover(), .id(), .bold(), .italic(), .fontWeight(), .underline(), .strikethrough(), .textCase(), .aspectRatio(), .scaledToFit(), .scaledToFill(), .fullScreenCover(), .tag(), .onSubmit(), .keyboardShortcut(), .focusedValue(), custom ViewModifier
@State, @Binding, @ObservedObject, @StateObject, @EnvironmentObject, @Published, @FocusState, @FocusedValue (active-window scoped; true focus-chain semantics deferred)
- Define the view struct in
Sources/SwiftOpenUI/Views/— pure data,Body = Never - Add backend rendering in each backend's Renderer as
extension MyView: PlatformRenderable - Add tests in
Tests/SwiftOpenUITests/ - See
docs/guides/adding-a-backend.mdfor the full pattern
- Define the modifier view struct in
Sources/SwiftOpenUI/Modifiers/withBody = Never - Add the
extension Viewconvenience method - Add backend rendering extensions in each Renderer
- Add tests
- Showcase: HelloWorld, Stopwatch, ColorMixer, Calculator, SimplePaint, LayoutStress (in
Examples/Showcase/) - Parity: ParityViewsBasic, ParityViewsLayout, ParityViewsContainers, ParityModifiers, ParityStateData, ParityNavigation, ParityEnvironment, ParityGestures, ParityAnimation, ParityFocus, ParityAppStructure (in
Examples/Parity/) - Plan:
docs/guides/examples-plan.md— two-track Showcase + Parity design - Rules: single
main.swiftper example, compiles and runs on all platforms (Android exception: uses flat views in JNIBridge.swift due to import conflict — seedocs/guides/examples-plan.md), platform limitations labeled inline with fallback text (never build errors) - Import boilerplate:
#if os(macOS) import SwiftUI #else import SwiftOpenUI + backend imports #endif - Entry point:
#if os(macOS) App.main() #elseif canImport(BackendGTK4) GTK4Backend().run() ...
| Doc | Purpose |
|---|---|
docs/guides/getting-started.md |
Setup, build, run on all platforms |
docs/guides/adding-a-backend.md |
How to implement a new backend |
docs/guides/examples-plan.md |
Examples reorganization plan |
docs/guides/web-setup.md |
Web/Wasm build, Vite, screenshots, DOM mapping |
docs/guides/android-setup.md |
Android cross-compilation setup |
docs/architecture/rendering-backends.md |
Backend architecture, ViewHost patterns |
docs/architecture/logical-coordinates.md |
Every dimension is a logical point; how each backend scales (Win32 px() chokepoint) |
docs/architecture/gtk4-animation-pipeline.md |
GTK4 animation: CSS transitions, transform composition, descriptors |
docs/architecture/web-animation-two-phase-rebuild.md |
Web animation: two-phase DOM rebuild, marker-based pairing, token lifecycle |
docs/architecture/android-backend-design.md |
Android backend design (batched JNI diffs) |
docs/porting/platform-notes.md |
Platform quirks: macOS, Linux, Windows, Web, Android |
docs/issues/observable-namespace-conflict.md |
ObservableObject/Published clash on macOS |
docs/plans/simplepaint-example.md |
SimplePaint example design and scope |
docs/proposals/unified-canvas-api.md |
Unified Canvas API proposal (Path, Shading, StrokeStyle) |
docs/architecture/app-bundle-format.md |
Cross-platform .app bundle format spec |
docs/guides/app-bundle-packaging.md |
App bundle packaging guide + SPM plugin usage |
~/Projects/SwiftLinuxUI— POC for Linux (GTK4), 150 commits, v0.28.0~/Projects/SwiftWindowsUI— POC for Windows (Win32/D2D), 81 source files- These are references only — SwiftOpenUI has its own architecture
When a response finishes a piece of work or a report, and there are clear follow-ups, end it with a short Next suggested actions list:
- 1–3 concrete actions, most useful first (for example: push and open a PR, file an issue for a bug found along the way, run a check that was skipped).
- Name what each one acts on (branch, issue, file, command), so the user can answer "do 1".
- Mark any that are outward-facing or hard to undo (push, merge, close an issue, delete).
- Skip the list for quick answers, mid-task updates, or when nothing obvious follows. Don't pad it.