A native macOS photo browser built with SwiftUI. Add local folders as "collections" and browse, search, and slideshow your photos. A companion desktop widget displays a rotating slideshow from a chosen collection.

- Browse photos from any local folder
- Organize multiple folders as named collections
- Search photos by filename or content
- Full-screen photo detail view
- Slideshow mode
- macOS desktop widget with smart cropping (face detection + saliency)
- Password-protect individual collections
- macOS 26+
- Xcode 26+
- Open
Shoebox.xcodeprojin Xcode. - Set your Development Team in the Signing & Capabilities tab for both the
ShoeboxandShoeboxWidgettargets. - Build and run (Cmd+R).
The app is sandboxed and uses an App Group (group.net.sub-pop.shoebox) for sharing data between the main app and the widget. Xcode will provision this automatically when a valid team is configured.
Shoebox/
├── Shoebox/ # Main app target
│ ├── ShoeboxApp.swift # App entry point
│ ├── ContentView.swift # Root view (NavigationSplitView)
│ ├── Info.plist
│ ├── Shoebox.entitlements
│ ├── Models/
│ │ ├── PhotoItem.swift # Single photo model
│ │ └── PhotoCollection.swift # Folder collection model (Codable)
│ ├── Views/
│ │ ├── CollectionSettingsView.swift
│ │ ├── EmptyStateView.swift
│ │ ├── FavoriteButton.swift
│ │ ├── GlassCircleButton.swift
│ │ ├── LockedCollectionView.swift
│ │ ├── PhotoDetailView.swift
│ │ ├── PhotoGridView.swift
│ │ ├── ShareButton.swift
│ │ └── SidebarView.swift
│ └── Services/
│ ├── CollectionManager.swift # Collection CRUD, persistence, widget export
│ ├── FavoritesManager.swift # Per-collection photo favorites
│ ├── FolderWatcher.swift # DispatchSource folder-change monitor
│ ├── ImageIndexer.swift # On-device image content indexing
│ ├── PhotoLoader.swift # Async folder scanning
│ ├── SmartCropper.swift # Vision-based face/saliency focus point
│ ├── ThumbnailCache.swift # In-memory NSCache-backed thumbnail actor
│ └── ThumbnailGenerator.swift # Thumbnail creation for widget export
├── Shared/
│ └── ShoeboxKit.swift # Constants & utilities shared between app and widget
├── ShoeboxWidget/ # WidgetKit extension target
│ ├── ShoeboxWidget.swift
│ ├── ShoeboxWidgetBundle.swift
│ ├── CollectionAppEntity.swift # AppEntity for widget configuration
│ ├── SelectCollectionIntent.swift # App intent for collection picker
│ ├── ShoeboxWidget.entitlements
│ └── Info.plist
└── Shoebox.xcodeproj/
- Collections are persisted as JSON in shared
UserDefaults(via App Group). Each collection stores a security-scoped bookmark for sandbox-safe folder access. The App Group identifier is read fromInfo.plist, derived from the XcodeDEVELOPMENT_TEAMbuild setting. - Favorites are tracked by photo ID in shared
UserDefaults.FavoritesManagersupports toggling, bulk removal by directory, and pruning stale entries. - FolderWatcher monitors collection directories for changes using FSEvents and debounces rapid filesystem events before triggering a reload.
- ImageIndexer runs Vision classification, text recognition, and feature-print extraction on each photo. Results are cached to disk as JSON per collection. The index powers keyword search (tags and OCR text) and visual-similarity search (feature-print distance).
- ThumbnailCache is a Swift actor backed by
NSCache(500 items / 150 MB limit) with a SHA256-keyed JPEG disk cache. Cached thumbnails are automatically invalidated when the source file's modification date is newer. - ThumbnailGenerator uses ImageIO (
CGImageSource) for efficient, EXIF-orientation-aware thumbnail creation. It is used by bothThumbnailCacheand widget export. - Widget export writes up to 48 JPEG thumbnails to the shared App Group container along with a
focus_points.jsonmanifest. The widget reads these at timeline refresh. - SmartCropper uses the Vision framework for face detection with an attention-based saliency fallback to compute a focus point for smart cropping in the widget.