This repo contains 3 components:
server/Node.js WebSocket relayapps/macos-controller/SwiftUI macOS controller appapps/ios-haptics/SwiftUI iOS receiver app with Core Haptics
get-me-my-iphone/
README.md
server/
index.js
package.json
README.md
apps/
macos-controller/
macos-controller/
macos_controllerApp.swift
ContentView.swift
MacControllerViewModel.swift
MacWebSocketClient.swift
HapticCommand.swift
Resources/
Info.plist
ios-haptics/
ios-haptics/
ios_hapticsApp.swift
ContentView.swift
IOSHapticsViewModel.swift
IOSWebSocketClient.swift
HapticsManager.swift
HapticCommand.swift
Resources/
Info.plist
cd server
npm install
npm startServer listens on ws://0.0.0.0:8080 by default.
Optional custom port:
PORT=9000 npm start- Open Xcode and create a new macOS
Appproject (SwiftUI + Swift). - Replace generated Swift source files with files from:
apps/macos-controller/macos-controller/
- In target settings, set your app entry file to
macos_controllerApp.swift. - Ensure
Info.plistincludes App Transport Security for localws://development:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>- Build and run on macOS.
- Enter server URL (
ws://<your-mac-lan-ip>:8080) and clickConnect.
- Open Xcode and create a new iOS
Appproject (SwiftUI + Swift). - Replace generated Swift source files with files from:
apps/ios-haptics/ios-haptics/
- In target settings, set your app entry file to
ios_hapticsApp.swift. - Add the same ATS exception in iOS
Info.plistfor localws://testing:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>- Run on a physical iPhone (Core Haptics is not reliable in simulator).
- Use the same server URL as macOS app (
ws://<your-mac-lan-ip>:8080) and connect.
Commands are sent as JSON text over WebSocket:
{ "type": "tap" }
{ "type": "buzz" }
{ "type": "pulse" }
{ "type": "buzz", "intensity": 0.8 }Extra command used by controller:
{ "type": "pattern_a", "intensity": 0.8 }tap: short transient hapticbuzz: continuous haptic for ~1 secondpulse: 4 short pulsespattern_a: custom mixed pattern
If Core Haptics is unavailable, commands are safely ignored.
Both Swift apps auto-reconnect using exponential backoff:
- starts at 1 second
- doubles up to 10 seconds max
- For production, use
wss://and remove broad ATS exceptions. - Consider adding client IDs / roles if you want server-side filtering.