Turn an iPad into a correctly mapped, low-latency Mac display.
One persistent BetterDisplay screen. Two exact profiles. Sunshine always pointed at the right macOS display. VoidLink tuned for 1600×1200 at 120 FPS.
🌐 Repository · 🇫🇷 Guide français · ⚙️ iPad settings · 🧯 Troubleshooting · 🔒 Security
This repository packages the setup that fixed three recurring problems on a Mac streamed to an iPad: offset mouse clicks, black bars, and a stream stuck well below the requested refresh rate. It includes the display switcher, wake recovery, safe Apple Shortcut recipes, the measured VoidLink profile, and an optional experimental Sunshine patch for macOS input and microphone redirect.
It is a community setup, not an official Sunshine, BetterDisplay, VoidLink, or Tailscale project.
- Sunshine on the Mac
- BetterDisplay on the Mac
- VoidLink on the iPad
Create one persistent Virtual Screen, keep it connected, and add:
| Profile | Exact mode | Purpose |
|---|---|---|
| iPad | 1600×1200 at 120 Hz | Native 4:3 canvas without black bars |
| TV / LG | 3440×1440 at 100 Hz, non-HiDPI | Optional ultrawide target |
Do not create one Virtual Screen per destination. Both profiles must reuse the same durable BetterDisplay tag ID. See the BetterDisplay guide.
git clone https://github.com/iamsupersocks/sunshine-voidlink-macos.git
cd sunshine-voidlink-macos
./install.shThe installer creates a local configuration file but does not overwrite an existing one.
Edit:
~/.config/sunshine-voidlink-macos/config.zsh
Set your BetterDisplay tag ID and, if needed, the path to your Sunshine app. Never copy another Mac’s display ID: the scripts resolve the live macOS ID on every switch.
"$HOME/Library/Application Support/Sunshine VoidLink/switch-virtual-screen.zsh" ipadThen apply the validated VoidLink settings and reconnect the session completely.
| Capability | Included |
|---|---|
| Correct absolute pointer mapping | Live BetterDisplay display ID → Sunshine output synchronization |
| iPad and ultrawide switching | One durable Virtual Screen with two exact modes |
| Wake recovery | Native macOS observer plus encoder-health watchdog |
| Apple Shortcuts | Safe action recipes for iPad, TV and remote wake |
| Remote wake | Placeholder-only Wake-on-LAN relay for a trusted LAN |
| High-FPS tuning | Documented software x264 reference profile |
| iPad microphone redirect | Optional source patch; no unsigned binary shipped |
| Fork safety | Local config ignored, privacy scanner included |
The cursor problem was not primarily a VoidLink sensitivity issue. Sunshine could capture one display while macOS calculated absolute pointer coordinates for another display geometry.
This project keeps the capture topology deterministic:
flowchart LR
Shortcut["iPad / TV Shortcut"] --> Profile["Select exact mode"]
Profile --> Screen["One persistent BetterDisplay Virtual Screen"]
Screen --> Identity["Read live macOS display ID"]
Identity --> Config["Update Sunshine output_name atomically"]
Config --> Restart["Restart and validate Sunshine"]
Restart --> Client["VoidLink reconnects with matching geometry"]
Normal profile changes never disconnect or recreate the Virtual Screen. That stable identity is the important part of the fix.
| Video | Value |
|---|---|
| Resolution | 1600×1200 custom |
| Frame rate | 120 FPS |
| Bitrate ceiling | 60 Mbps |
| Codec | H.264 |
| Frame pacing | Queue Buffering |
| Frames to buffer | 1 |
| Async Frame Dequeue | Off |
| HDR / YUV 4:4:4 / PiP | Off |
| Input | Value |
|---|---|
| Local Mouse Cursor | Visible |
| Touch Mode | Disabled |
| Touch Point Tracking | Off |
| External Display Mode | Duplicate |
| Redirect Mic / Built-in Mic | On |
| Audio | Stereo (SDL) |
Visible is intentional for the reference setup: Captured immobilized the physical pointer and Hidden produced confusing local/remote cursor behavior. Your iPadOS version or mouse may differ, so test this setting before changing the display topology.
Open the original sanitized settings captures
The personal desktop captures were deliberately excluded. These images were converted to clean PNG files and scanned for personal metadata.
The reference machine is an Apple M1 Pro with a 10-core CPU. Its working software profile was:
minimum_fps_target = 190
max_bitrate = 60000
encoder = software
sw_preset = ultrafast
sw_tune = zerolatency
min_threads = 10
fec_percentage = 5Do not treat those values as universal defaults. Ten software-encoding threads can increase CPU use, heat, and battery drain.
| Stage | Observed stream rate |
|---|---|
| VideoToolbox path in this build | 43–45 FPS |
| Software x264, 2 threads | about 91 FPS |
| Software x264, 10 threads | about 98 FPS |
| Higher internal capture target | peaks around 109 FPS |
| Final reference profile | roughly 90–122 FPS |
The 1 Gbps Mac Ethernet adapter removed a local host-side bottleneck. It did not create FPS by itself, and it does not justify a 1000 Mbps stream bitrate. At 1600×1200/120, 60 Mbps is the validated starting point. Increase bitrate only for visible compression while network drops remain at zero.
Read Performance and 120 FPS tuning before changing the encoder profile.
The measured result matters less than the method used to reach it. Read Lessons learned for the decisions that prevented cursor regressions, unnecessary bitrate increases, and a misleading “120 FPS” that only fills a client-side queue.
The repository intentionally ships recipes instead of signed Shortcut exports. Exports can silently retain SSH hosts, usernames, or keys.
Included recipes:
- VoidLink — iPad: apply the 1600×1200/120 profile;
- VoidLink — TV: apply the 3440×1440/100 profile;
- Open Mac: use a restricted SSH command on the reachable Mac;
- Remote Wake: ask an always-on LAN relay to send Wake-on-LAN, then open VoidLink.
Build them in a few actions with the Shortcuts guide. Existing local shortcuts named VSSH or iPad SSH map to the same restricted SSH recipe; only the reachable network path changes.
| Path | Use it when |
|---|---|
| Official Sunshine build | You need display switching, pointer mapping and wake recovery only |
| Experimental source patch | You also need client-microphone redirect or the included macOS input adjustments |
The patch targets Sunshine v2026.516.143833 and is distributed as source under GPL-3.0. No custom application binary is published. Keep an official build available for rollback. See patches/README.md.
assets/ Sanitized settings and README hero
config/ Public examples; real local values stay ignored
docs/ Setup, performance, security and troubleshooting
launchagents/ Wake recovery template
patches/ Optional Sunshine source patch
relay/ Optional Wake-on-LAN relay
shortcuts/ Safe Apple Shortcuts recipes
src/ Display switching and wake recovery
tests/ Offline profile, observer and privacy tests
./tests/test-switch-virtual-screen.zsh
./tests/test-encoder-watchdog.zsh
./tests/privacy-scan.zshThe display test uses a fake BetterDisplay backend. It proves that both profiles keep the same durable tag/display identity and that normal switching never issues a disconnect.
- 120 FPS is a request and tuning target, not a universal guarantee.
- BetterDisplay mode availability depends on the Mac and attached display.
- A sleeping Mac may need an always-on LAN relay for remote Wake-on-LAN.
- The microphone patch is experimental and tied to one upstream Sunshine tag.
- VoidLink option names can change between app releases.
- This setup does not expose Sunshine safely to the public Internet by itself.
UPnP is disabled in the public Sunshine example. Remote use should stay behind an authenticated private overlay such as Tailscale. SSH examples use dedicated keys restricted to a small allow-list of profile commands.
This repository contains no real key, IP address, MAC address, hostname, pairing state, signed Shortcut, browser profile, or personal desktop capture. Read the complete security notes.
Forks are encouraged. Hardware profiles and measured results are useful when they include:
- Mac model and macOS version;
- client and VoidLink version;
- exact resolution and refresh rate;
- delivered Video stream FPS;
- network and pacing drops;
- encoder choice.
See CONTRIBUTING.md before submitting captures or logs.
Built around the work of Sunshine, BetterDisplay, VoidLink, and optionally Tailscale.
Original scripts and documentation: MIT.
Sunshine derivative patch: GPL-3.0.



