A native macOS app in SwiftUI. It runs on this Mac only, with a local SwiftData database and no server.
Sources/FrameLoop/the app.App.swifthas the window, menus, and the database location.Sources/FrameLoopKit/rules and data logic with no SwiftUI. Tests inTests/FrameLoopKitTests/.Package.swifta Swift package. There is no Xcode project.build.shbuilds, signs, and installs/Applications/FrameLoop.app.Icon/AppIcon.iconthe app icon, an Icon Composer file (JSON plus SVG layers).build.shcompiles it withtools/make_icon.sh;tools/icon_review.shrenders every look into one PNG.docs/the brief, the screen index, and the user stories, when they exist.
- Build and install:
./build.sh. Add--opento restart the app with the new build. The build shows warnings; fix them. - Unit tests:
swift test --scratch-path ~/Library/Developer/FrameLoop/test-build. - Self-test (the app's real functions on a /tmp store):
tools/selftest.sh. Exit 0 when every check passes. Add a check for every story with logic inSelfTest.swift. - After every UI change, take snapshots with sample data and look at them:
tools/snap.sh. It writes/tmp/FrameLoop-shots/<page>-light.pngand-dark.pngfor every sidebar page, andsettings-<tab>-light.pngand-dark.pngfor every Settings tab, then quits.APP_SNAPSHOT_PAGES=all,settings tools/snap.shlimits the pages. For a panel, sheet, or popover, add a capture toSnapshot.swiftlike the Settings loop. - Snapshots, seed data, and the self-test refuse to run without
APP_STOREin /tmp. - Never test against the real database in
~/Library/Application Support/FrameLoop/. - Then check the grid:
tools/grid-lint.shandswift tools/check-layout.swift /tmp/FrameLoop-shots/*-layout.json. Both print PASS. - A change is done when the build has no errors, the grid checks pass, and you looked at the light and dark snapshots.
- Run the app through
open(tools/selftest.sh and tools/snap.sh do). A binary started straight from a shell can come up with no window. - Builds need Xcode's toolchain: the command-line tools' SwiftPM is broken on this Mac. Run
export DEVELOPER_DIR="/Volumes/OWC Express 1M2 001/Xcode.app/Contents/Developer"first. - Snapshots of the main window are degraded (blank sidebar, glass, and video) until the app that runs them has Screen Recording permission.
- Icon build needs
sudo xcodebuild -runFirstLaunchonce; until then build.sh skips the icon. - The bundle identifier remains
com.robschoen.frameloop2to preserve existing preferences after the rename. - Stories live in docs/STORIES.md; the old Electron app is in ~/Dropbox/CC/FrameLoop for behavior reference.
- Use Apple's controls and system styles. Only the accent color is custom:
UI/Theme.swift(ThemeStore.defaultID). People change it, and light or dark mode, in Settings > Appearance. - Views use
.tint,Palette.accent,Palette.accentText(accent-colored text), andPalette.onAccent(text on an accent fill). Never hard-code colors, radii, or durations in views. - Compare accents: add
APP_ACCENT=<id>to the snapshot command. - Spacing comes from
SpaceinUI/Grid.swift, on a 4 pt grid. Mark custom pages and cards with.gridAreaand.gridProbe. - Windows open calm:
.noInitialFocus()on every window and sheet (no focus ring or selected text on open),.fitsContent()on sheets and Settings tabs (no scroll bar with nothing to scroll). System scroll bars. Both inUI/WindowBehavior.swift. - Settings: one tab per topic in
SettingsView.swift, one grouped Form per tab. Add a case toSettingsTabfor a new tab. - Window chrome (title bar, toolbar, sidebar, menus, sheets) stays system. Buttons use system styles, like
.borderedProminent. - Colors:
.primary,.secondary,.tint, and system colors. Never fixed grays or white for text. - Every action has a menu bar item and a keyboard shortcut.
Labelfor icon and text pairs. SF Symbols for icons.ContentUnavailableViewfor empty states.- Liquid Glass belongs to floating controls only, never to content.
The bama plugin has a skill for each step: mac-design (design rules),
design-system (accent and tokens), layout-grid, ux-design,
swift-swiftui, os-integrations, performance, build-and-verify,
test-mac-app, app-icon, user-stories, and improve-loop. Use them.
- Commit after each working change, with a message that says what the user can now do.