Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

gabrieldonadel/entangle

Open more actions menu

Repository files navigation

Entangle — your Mac's pointer, in your pocket.

License: MIT macOS iOS Android Stars


Turn your phone into a trackpad for your Mac. Free, open‑source, zero‑setup. Stays on your Wi‑Fi, never leaves the room.


↓ Download · ⚡ Quick start · 🛠 Hack on it ·



✨ Why Entangle?

You're across the room. The Mac is plugged into the TV. The keyboard is buried under cables. Pick up your phone instead.

Feature What you get
🖱 Trackpad mode Smooth, sub‑frame pointer with two‑finger scroll & tap‑to‑click.
⌨️ Keyboard relay Type from your phone. Modifier keys, arrows, the works.
🔒 LAN‑only by default No accounts, no cloud, no telemetry. Pairs over the local network.
📡 Auto‑discovery Bonjour / mDNS finds your Mac the moment the app opens.
🌓 Native everywhere React Native macOS on desktop, Expo on mobile. One repo.

🔌 How it works

Phone → LAN → Mac

The mobile app advertises itself over Bonjour / mDNS. The desktop daemon listens on the LAN, the phone connects, and from then on every gesture is a tiny WebSocket frame on your local network. No relay servers. No internet required. If your router goes down, Entangle keeps working.

The wire format is a single shared TypeScript package — @entangle/protocol — imported by both clients, so the desktop and the phone can never disagree about what a message looks like.


📥 Install

From a release

Platform Download
macOS (Apple Silicon) Entangle.dmg
iOS App Store
Android Google Play · entangle.apk

Build from source

# 1. Clone
git clone https://github.com/gabrieldonadel/entangle.git
cd entangle

# 2. Install dependencies
pnpm install

# 3. CocoaPods for the desktop app (first clone only)
cd apps/desktop/macos && bundle install && bundle exec pod install && cd -

# 4. Run the desktop app
pnpm desktop:start    # in one terminal — Metro on port 8090
pnpm desktop:macos    # in another     — build & launch the macOS app

# 5. Run the mobile app
pnpm mobile:start     # Expo dev server
pnpm mobile:ios       # iOS simulator / device
pnpm mobile:android   # Android emulator / device

That's it. The phone will find the Mac on its own — pick it from the discovered list and start moving the pointer. macOS will ask for Accessibility permission the first time; the desktop UI is gated until you grant it.


🧰 Requirements

Node.js ≥ 18
pnpm 10.x
Xcode 15+ (for iOS & macOS builds)
CocoaPods bundle install && bundle exec pod install inside apps/desktop/macos
Accessibility macOS Accessibility permission — required to synthesize pointer / keyboard input

📦 What's in the box

entangle-monorepo/
├─ apps/
│  ├─ desktop/      ← React Native macOS 0.81 + Expo 55  (the macOS server)
│  ├─ mobile/       ← Expo 55 + Expo Router + RN 0.83    (iOS / Android client)
│  └─ website/      ← Vite + React 18                    (marketing site)
├─ packages/
│  └─ shared/       ← @entangle/protocol — shared wire format (TypeScript)
├─ pnpm-workspace.yaml
└─ pnpm-lock.yaml
App Path Platforms Stack
Desktop apps/desktop macOS React Native macOS 0.81 + Expo 55, React 19.1
Mobile apps/mobile iOS / Android Expo 55 + Expo Router + RN 0.83, React 19.2
Website apps/website Web Vite + React 18

One workspace, one lockfile. Apps and shared packages all live in the same pnpm workspace. The root .npmrc sets node-linker=hoisted so each app gets a flat node_modules tree — conflicting versions (e.g. desktop's react-native@0.83.6 vs mobile's react-native@0.83.4) get nested under the consuming app, while shared deps hoist to the root. Patches for the macOS port of Expo are pinned to specific versions in pnpm-workspace.yaml so they only touch the version desktop resolves to.


🛠 Development

pnpm lint                               # eslint across every workspace
pnpm desktop test                       # jest (desktop unit tests)
pnpm desktop test -- path/to/file.test  # single test file
pnpm desktop <cmd>                      # forward any command into apps/desktop
pnpm mobile <cmd>                       # forward any command into apps/mobile

packages/shared is the source of truth for messages on the wire — touch it once, both clients update. All wire messages carry v: 1; bump PROTOCOL_VERSION for breaking changes and the server will close mismatched clients with code 4001.


🗺 Roadmap

  • Trackpad + scroll + tap‑to‑click
  • Keyboard relay
  • mDNS auto‑discovery
  • Dock enumeration & app activation
  • Media keys & system shortcuts
  • Windows desktop client
  • Apple Watch quick‑actions

See open issues for the live picture.


🤝 Contributing

PRs welcome — small fixes don't need an issue first. For anything bigger, open an issue and let's chat.

  1. Fork & branch (feat/your-thing)
  2. pnpm install at the root — that's it; apps share a single workspace
  3. Commit with Conventional Commits
  4. Open a PR against main

📄 License

MIT © Gabriel Donadel. See LICENSE for details.



Enjoying Entangle? Drop a ⭐.

Made with React Native macOS + Expo · No trackers · No analytics · No nonsense

About

A free and open‑source remote mouse app to control your desktop from your phone

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.