macOS Native App AI Development Guide
This document is intended for AI assistants to guide the development of Presto's future macOS native version. As of March 2026, extracted from
Presto/docs/native-app-refactoring.md.
Scope
This guide applies to:
- Target project: Presto's future macOS native version (Swift + SwiftUI)
- Current status: Presto is currently a Go + SvelteKit + Wails application; this document prepares for a future refactor
- AI assistant role: Generate code following Apple HIG principles and SwiftUI best practices
Note: The current Presto repository contains no Swift code. This document is a preparatory specification.
Tech Stack
| Layer | Technology | Version | Notes |
|---|---|---|---|
| Language | Swift | 6.0 | Swift Concurrency (async/await, actors) |
| UI Framework | SwiftUI | 5.0 | @Observable macro, NavigationSplitView |
| Persistence | SwiftData | 1.0 | @Model macro, CloudKit integration |
| Platform | macOS | 14.0+ | Sonoma and above |
| Platform | iOS/iPadOS | 17.0+ | iPhone and iPad (optional) |
| Typesetting | Typst | 0.14.2 | Via CLI or library call |
| Build Tool | Xcode | 16.0+ | Swift Package Manager |
Apple HIG Core Principles
All AI-generated UI code must follow these four principles:
1. Clarity
- Interfaces are easy to understand, with legible text and sharp icons
- Clear visual hierarchy so users can identify focus at a glance
- In practice: Use system fonts (SF Pro), standard sizes, high-contrast color schemes
2. Deference
- UI steps back to let content take center stage
- Use translucency, blur, and subtle UI elements
- In practice: Avoid excessive decoration, use standard system controls (
.buttonStyle(.bordered))
3. Depth
- Visual layers and fluid transitions help users understand position and navigation relationships
- In practice: Use NavigationStack/NavigationSplitView, system transition animations
4. Consistency
- Maintain consistent interaction patterns within the app and across platforms
- In practice: Follow macOS menu bar conventions, standard keyboard shortcuts, system icons (SF Symbols)
SwiftUI Code Conventions
Architecture Pattern
Use the MVVM + Repository pattern:
// Model: SwiftData @Model
@Model
final class RecentDocument {
var fileURL: URL
var lastOpened: Date
}
// ViewModel: @Observable
@Observable
final class ConversionPipeline {
var isConverting = false
var previewPages: [PreviewPage] = []
func convert(markdown: String, templateId: String) async throws { }
}
// Repository: actor isolation
actor TemplateManager {
func listTemplates() throws -> [InstalledTemplate] { }
}
// View: SwiftUI
struct ContentView: View {
@Binding var document: PrestoDocument
@StateObject private var pipeline = ConversionPipeline()
}Component Naming Conventions
| Type | Naming Rule | Examples |
|---|---|---|
| View | Feature + View suffix | ContentView, MarkdownEditorView |
| ViewModel | Feature + no suffix | ConversionPipeline, ScrollSyncManager |
| Model | Noun, no suffix | RecentDocument, Manifest |
| Repository | Feature + Manager | TemplateManager, TypstCompiler |
| Protocol | Feature + Service | PrestoService |
| Enum | Noun | PageContent, EditorTheme |
State Management
Use the SwiftUI 5 @Observable macro (NOT @ObservableObject):
@Observable
final class ConversionPipeline {
var isConverting = false // Automatically triggers UI updates
var typstSource: String = ""
func convert() async { }
}
// Usage in View
struct ContentView: View {
@State private var pipeline = ConversionPipeline()
// Or inject via @Environment
}Property wrapper selection:
| Wrapper | Usage | Example |
|---|---|---|
@State | View-local mutable state | @State private var showSheet = false |
@Binding | Two-way binding | @Binding var text: String |
@Observable | Observable object | @Observable final class VM { } |
@Environment | Global dependency injection | @Environment(\.openDocument) |
@AppStorage | UserDefaults | @AppStorage("fontSize") var fontSize = 14 |
Navigation Patterns
macOS three-column layout:
NavigationSplitView {
// Sidebar: File navigation, template list
SidebarView()
} detail: {
// Main Content
HSplitView {
MarkdownEditorView()
DocumentPreview()
}
}iOS/iPadOS adaptive layout:
NavigationStack {
// iPhone: Single column
// iPad landscape: Split View
// iPad portrait: Tab switching
}macOS-Specific Conventions
Menu Bar Structure
Standard menus (auto-generated by macOS):
- App menu: About Presto, Preferences (Command-,), Quit (Command-Q)
- File menu: New (Command-N), Open (Command-O), Save (Command-S), Export PDF (Command-E)
- Edit menu: Undo (Command-Z), Redo (Command-Shift-Z), Cut, Copy, Paste, Find (Command-F)
- View menu: Show/Hide Sidebar (Command-Shift-S), Show Preview (Command-Shift-P)
Custom menus (via SwiftUI Commands):
struct PrestoMenuCommands: Commands {
var body: some Commands {
CommandMenu("Typesetting") {
Button("Switch Template") { }
.keyboardShortcut("t")
Button("Compile & Preview") { }
.keyboardShortcut("r")
}
}
}Keyboard Shortcuts
| Shortcut | Action | Notes |
|---|---|---|
Command-O | Open file | Cross-platform |
Command-S | Save | System default |
Command-E | Export PDF | Custom |
Command-T | Switch template | Custom |
Command-R | Compile & preview | Custom |
Command-Shift-P | Show/Hide preview | macOS |
Control-Command-1/2/3 | Switch view mode | macOS |
Code example:
.buttonStyle(.bordered)
.keyboardShortcut("e", modifiers: .command)Window Management
Singleton windows (Settings, Template Store):
@main
struct PrestoApp: App {
var body: some Scene {
DocumentGroup(newDocument: PrestoDocument()) { file in
ContentView(document: file.$document)
}
#if os(macOS)
Settings {
SettingsView()
}
Window("Template Store", id: "template-store") {
TemplateStoreView()
}
.defaultSize(width: 800, height: 600)
#endif
}
}Window size constraints:
.frame(minWidth: 800, minHeight: 600)
.frame(maxWidth: .infinity, maxHeight: .infinity)System Integration
Spotlight Search:
- Index via
NSUserActivity - Core Spotlight API for document content indexing
Quick Look Preview:
.quickLookPreview($selectedDocumentURL)Share Extension:
.shareLink(item: pdfData, preview: SharePreview("document.pdf", image: thumbnail))Drag and Drop support:
.onDrop(of: [.fileURL], isTargeted: nil) { providers in
// Handle file drop
}Accessibility Requirements
Full VoiceOver support:
MarkdownEditorView(text: $document.markdown)
.accessibilityLabel("Markdown Editor")
.accessibilityHint("Enter Markdown content here")
DocumentPreview(pages: pipeline.previewPages)
.accessibilityLabel("Document Preview")
.accessibilityValue("\(pages.count) pages total")Dynamic Type support:
@Environment(\.sizeCategory) var sizeCategory
var editorFont: Font {
.system(
size: UIFontMetrics.default.scaledValue(for: 14),
design: .monospaced
)
}Reduce Motion adaptation:
@Environment(\.accessibilityReduceMotion) var reduceMotion
.animation(reduceMotion ? nil : .easeInOut(duration: 0.2), value: isConverting)Minimum touch target:
- All interactive elements must be at least 44x44 pt
- macOS may use slightly smaller targets (mouse precision), but iOS must comply
Prohibited Practices
Do not use deprecated APIs:
- No
NavigationView-- useNavigationStack/NavigationSplitView - No
@ObservableObject-- use@Observable(SwiftUI 5) - No
UIAlertController-- use SwiftUI.alert()modifier
Do not hard-code dimensions:
- No
.frame(width: 375, height: 812)(iPhone dimensions) - Use
.frame(maxWidth: .infinity)or GeometryReader instead
Do not ignore accessibility:
- No visual-only feedback (color changes only)
- Use VoiceOver labels + Dynamic Type + Reduce Motion
Do not override system behavior:
- No overriding
Command-Qquit logic - Use standard system behavior
Do not perform time-consuming operations on the main thread:
- No synchronous Typst compilation
- Use
Task { try await typstCompiler.compile() }
Do not use unsupported APIs across platforms:
- No calling
NSOpenPanelon iOS - Use
#if os(macOS)conditional compilation
Reference Resources
Apple official documentation:
Presto internal documentation:
Presto/docs/native-app-refactoring.md-- Complete refactoring plan (97KB, detailed architecture design)Presto-homepage/docs/ai-guide.md-- Organization-level AI development guide
Key design decisions:
- Prefer PDFKit for PDF rendering over SVG (Apple has no public runtime SVG rendering API)
- Document-Based App architecture (
DocumentGroup), with automatic iCloud Drive support - Template binaries executed via
Process(macOS); iOS uses Swift-native built-in templates - SwiftUI + SwiftData + CloudKit for iCloud three-device sync
2025-2026 trends:
- Liquid Glass design language (WWDC25)
- visionOS spatial computing guidelines (if Vision Pro support is needed)
- Apple Intelligence AI integration guide
Last updated: 2026-03-01 Based on: Presto/docs/native-app-refactoring.md (as of March 2026)
