This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
SpreadPaper is a native macOS app (Swift 6 / SwiftUI) that spreads a single high-resolution image across multiple monitors as wallpaper. Requires macOS 15.0+ (Sequoia) and Apple Silicon. The repo also contains a Vite + Tailwind CSS marketing website.
macOS App (Xcode):
open SpreadPaper.xcodeproj # Open in Xcode, then Cmd+R to build/run
xcodebuild -scheme SpreadPaper -configuration Debug build # CLI buildWebsite:
npm ci
npm run dev # Local dev server
npm run build # Production build to dist/The app has only 4 Swift source files:
- SpreadPaperApp.swift — App entry point, integrates UpdateChecker on launch
- ContentView.swift (~950 lines) — All UI and core logic:
WallpaperManager(ObservableObject) — Screen detection, image rendering via CGContext, wallpaper application viaNSWorkspace.setDesktopImageURL(), preset persistence as JSONSavedPreset/DisplayInfo/AppSettings— Data models- NavigationSplitView layout with sidebar (presets) and detail (canvas editor)
- UpdateChecker.swift — Fetches latest GitHub release, parses CHANGELOG.md for version history
- UpdatePopupView.swift — Update notification popup UI
- Images are stored in
~/Library/Application Support/SpreadPaper/with UUID filenames - Per-screen wallpapers saved as
spreadpaper_wall_{screenName}_{timestamp}.png - Old wallpapers are auto-cleaned on reapplication
- Multi-monitor rendering uses CGContext with coordinate transforms to handle scaling, offsets, and image flipping across displays
- Presets serialized to
spreadpaper_presets.jsonin the app support directory
Entitlements: sandbox enabled, user-selected read-only file access, network client (for update checking). App is not code-signed with a paid Apple Developer ID.
Automated via GitHub Actions with release-please:
- Pushes to
maintrigger release-please to create/update release PRs - On release, the app is archived with
xcodebuild, ad-hoc signed, and distributed as both DMG and ZIP - Version is sourced from
.release-please-manifest.jsonand synced into the Xcode project'sMARKETING_VERSIONandCURRENT_PROJECT_VERSION
- Swift 6 strict concurrency
- SwiftUI with
@StateObjectfor managers,@Statefor local UI state,@AppStoragefor persisted settings - Combine for async operations (update checker)
- Conventional commits (feat/fix/chore) — release-please generates CHANGELOG.md from these