|
| 1 | +# PinStick — Development & Porting Guide |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +PinStick is a lightweight macOS note-pinning app (formerly named "Jot") built with Swift/SwiftUI. It lives in the `SillyLittleTech/PinStick` repository. |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## Branch Strategy |
| 10 | + |
| 11 | +| Branch | Purpose | |
| 12 | +|---|---| |
| 13 | +| `main` | Stable macOS app with ARM (Apple Silicon) support | |
| 14 | +| `cross-platform-dev` | Windows and Linux porting work | |
| 15 | + |
| 16 | +### Working Rules |
| 17 | +- All production-ready macOS changes merge into `main`. |
| 18 | +- Cross-platform experiments stay on `cross-platform-dev` until proven stable and tested. |
| 19 | +- Bug fixes that apply to both platforms should be cherry-picked from `main` into `cross-platform-dev` (or vice-versa) rather than duplicated. |
| 20 | +- Open a PR to `main` only when the cross-platform work is validated through CI. |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +## ARM Support (Apple Silicon) |
| 25 | + |
| 26 | +The app was originally built with x64 in mind. To make it ARM-native: |
| 27 | + |
| 28 | +### Xcode Build Settings |
| 29 | +1. Open `Jot.xcodeproj` (unzip `Jot.xcodeproj.zip` first). |
| 30 | +2. Select the **Jot** target → **Build Settings**. |
| 31 | +3. Set **Architectures** to `$(ARCHS_STANDARD)` (includes `arm64` + `x86_64` automatically). |
| 32 | +4. Set **Build Active Architecture Only** to `No` for Release builds. |
| 33 | +5. Under **Deployment**, set **macOS Deployment Target** to `14.0` or later (matching the current project) for full Apple Silicon support. |
| 34 | + |
| 35 | +### Verifying ARM Compatibility |
| 36 | +```bash |
| 37 | +# After building, check the binary supports both architectures |
| 38 | +lipo -info build/Release/PinStick.app/Contents/MacOS/PinStick |
| 39 | +# Expected: Architectures in the fat file: arm64 x86_64 |
| 40 | +``` |
| 41 | + |
| 42 | +### Testing Recommendations |
| 43 | +- Build and run on Apple Silicon hardware (M1/M2/M3). |
| 44 | +- Use GitHub Actions `macos-latest` runners — they run on Apple Silicon and will catch ARM-specific issues in CI. |
| 45 | +- Run existing unit tests (`JotTests`) after the architecture change to confirm no regressions. |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +## Windows & Linux Porting Strategy |
| 50 | + |
| 51 | +### Why Not a Full Rewrite Immediately? |
| 52 | +AI-generated cross-platform code can have platform-specific bugs that are impossible to catch without running the app. The strategy below uses CI runners and beta testers as the safety net, avoiding the need for local VMs. |
| 53 | + |
| 54 | +### Framework Options |
| 55 | + |
| 56 | +| Framework | Language | Pros | Cons | |
| 57 | +|---|---|---|---| |
| 58 | +| **Qt** | C++ | Native look, powerful, cross-platform | Steep learning curve, C++ | |
| 59 | +| **Tauri** | Rust + Web (HTML/CSS/JS) | Lightweight, modern, secure | Rust learning curve | |
| 60 | +| **Flutter** | Dart | Fast UI, growing desktop support | Non-native look by default | |
| 61 | +| **.NET MAUI** | C# | Microsoft-backed, good Windows support | Less mature on Linux | |
| 62 | +| **Electron** | JS/TypeScript | Easy, huge ecosystem | Large binary size | |
| 63 | + |
| 64 | +**Recommendation for PinStick**: Given the app's simplicity (note editor + pin-to-front), **Tauri** is the best fit — it produces small binaries, uses web tech for the UI, and has first-class GitHub Actions support. |
| 65 | + |
| 66 | +### Code Organization for Shared Logic |
| 67 | + |
| 68 | +``` |
| 69 | +PinStick/ |
| 70 | +├── shared/ # Business logic shared across platforms |
| 71 | +│ ├── models/ # Note data model |
| 72 | +│ └── storage/ # Persistence layer |
| 73 | +├── macos/ # Native Swift/SwiftUI macOS app |
| 74 | +│ └── Sources/ |
| 75 | +├── cross-platform/ # Tauri / Qt / Flutter app (cross-platform-dev branch) |
| 76 | +│ ├── src-tauri/ # Rust backend |
| 77 | +│ └── src/ # Web frontend (HTML/CSS/JS) |
| 78 | +└── .github/ |
| 79 | + └── workflows/ |
| 80 | +``` |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +## GitHub Actions CI/CD |
| 85 | + |
| 86 | +### Current Workflows |
| 87 | + |
| 88 | +| Workflow | Trigger | What It Does | |
| 89 | +|---|---|---| |
| 90 | +| `prerelease.yml` | PR marked ready for review | Builds macOS app, creates prerelease; includes Windows/Linux placeholder job for future ports | |
| 91 | +| `build-and-release.yml` | Push to `main` | Builds macOS app, tags release, publishes; includes Windows/Linux placeholder job for future ports | |
| 92 | + |
| 93 | +### Testing on Windows & Linux Without Local VMs |
| 94 | + |
| 95 | +GitHub Actions provides free hosted runners for all major platforms: |
| 96 | + |
| 97 | +```yaml |
| 98 | +strategy: |
| 99 | + matrix: |
| 100 | + os: [macos-latest, windows-latest, ubuntu-latest] |
| 101 | +runs-on: ${{ matrix.os }} |
| 102 | +``` |
| 103 | +
|
| 104 | +This lets CI compile and test the cross-platform build on actual Windows and Linux machines without installing anything locally. |
| 105 | +
|
| 106 | +#### Docker for Lightweight Linux Testing |
| 107 | +```yaml |
| 108 | +- name: Test on Linux (Docker) |
| 109 | + uses: addnab/docker-run-action@v3 |
| 110 | + with: |
| 111 | + image: ubuntu:22.04 |
| 112 | + run: | |
| 113 | + ./cross-platform/scripts/build-linux.sh |
| 114 | + ./cross-platform/scripts/test-linux.sh |
| 115 | +``` |
| 116 | +
|
| 117 | +#### Adding Cross-Platform Builds to Workflows (Future) |
| 118 | +When the cross-platform branch matures, extend `build-and-release.yml` with: |
| 119 | +```yaml |
| 120 | +- name: Build Windows App |
| 121 | + if: runner.os == 'Windows' |
| 122 | + run: | |
| 123 | + cd cross-platform |
| 124 | + npm run tauri build -- --target x86_64-pc-windows-msvc |
| 125 | +
|
| 126 | +- name: Build Linux App |
| 127 | + if: runner.os == 'Linux' |
| 128 | + run: | |
| 129 | + cd cross-platform |
| 130 | + npm run tauri build -- --target x86_64-unknown-linux-gnu |
| 131 | +``` |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +## Beta Testing Program |
| 136 | + |
| 137 | +For real-world validation without a local VM: |
| 138 | + |
| 139 | +1. **macOS** — TestFlight or direct `.app.zip` distribution via GitHub Releases. |
| 140 | +2. **Windows** — GitHub Releases `.exe` / `.msi` installer; recruit Windows beta testers. |
| 141 | +3. **Linux** — AppImage or Flatpak distributed via GitHub Releases. |
| 142 | + |
| 143 | +Collect crash reports using Sentry or a lightweight logging service to catch issues you can't reproduce locally. |
| 144 | + |
| 145 | +--- |
| 146 | + |
| 147 | +## Development Workflow |
| 148 | + |
| 149 | +### Working on the `cross-platform-dev` Branch |
| 150 | + |
| 151 | +```bash |
| 152 | +git fetch origin |
| 153 | +git checkout cross-platform-dev |
| 154 | +# Make changes, commit, push |
| 155 | +git push origin cross-platform-dev |
| 156 | +``` |
| 157 | + |
| 158 | +Opening a PR from `cross-platform-dev` → `main` will trigger the prerelease workflow, giving you a build artifact before merging. |
| 159 | + |
| 160 | +### Running CI Builds Without Merging |
| 161 | + |
| 162 | +Trigger the release workflow manually with `workflow_dispatch`: |
| 163 | + |
| 164 | +1. Go to **Actions** → **Build & Release macOS App**. |
| 165 | +2. Click **Run workflow**, set **draft** to `true`. |
| 166 | +3. GitHub will build and produce a draft release you can download and test. |
| 167 | + |
| 168 | +### Merging Strategy |
| 169 | + |
| 170 | +1. All Windows/Linux work stays on `cross-platform-dev`. |
| 171 | +2. When a platform is stable (passes CI, passes beta testing): |
| 172 | + - Open a PR from `cross-platform-dev` → `main`. |
| 173 | + - The prerelease workflow builds and uploads artifacts automatically. |
| 174 | + - After review and merge, the release workflow publishes the new version. |
| 175 | +3. Bump `MARKETING_VERSION` in `Jot.xcodeproj/project.pbxproj` before merging to trigger a new release tag. |
| 176 | + |
| 177 | +--- |
| 178 | + |
| 179 | +## Project Structure Notes |
| 180 | + |
| 181 | +``` |
| 182 | +PinStick/ |
| 183 | +├── Jot.xcodeproj.zip # Xcode project (unzip before building) |
| 184 | +├── PinStickApp.swift # App entry point + ContentView |
| 185 | +├── Item.swift # Data model |
| 186 | +├── Jot.entitlements # macOS sandbox entitlements |
| 187 | +├── Contents.json # AppIcon.xcassets icon catalog |
| 188 | +├── icon_*.png # App icon assets (all sizes) |
| 189 | +├── JotTests.swift # Unit tests |
| 190 | +├── JotUITests.swift # UI tests |
| 191 | +├── JotUITestsLaunchTests.swift |
| 192 | +└── .github/ |
| 193 | + ├── workflows/ |
| 194 | + │ ├── prerelease.yml # PR prerelease automation |
| 195 | + │ └── build-and-release.yml # Main branch release automation |
| 196 | + └── copilot-instructions.md # This file |
| 197 | +``` |
| 198 | +
|
| 199 | +### Asset Catalog Icon Sizes (macOS) |
| 200 | +
|
| 201 | +| File | Logical Size | Scale | |
| 202 | +|---|---|---| |
| 203 | +| `icon_16x16.png` | 16×16 | @1x | |
| 204 | +| `icon_32x32.png` | 16×16 | @2x | |
| 205 | +| `icon_32x32 1.png` | 32×32 | @1x | |
| 206 | +| `icon_64x64.png` | 32×32 | @2x | |
| 207 | +| `icon_128x128.png` | 128×128 | @1x | |
| 208 | +| `icon_256x256.png` | 128×128 | @2x | |
| 209 | +| `icon_256x256 1.png` | 256×256 | @1x | |
| 210 | +| `icon_512x512.png` | 256×256 | @2x | |
| 211 | +| `icon_512x512 1.png` | 512×512 | @1x | |
| 212 | +| `icon_1024x1024.png` | 512×512 | @2x | |
0 commit comments