PowerPointer turns your phone or tablet into a remote control for Microsoft PowerPoint. The Node.js server runs on the computer with PowerPoint, and the mobile device opens the address shown by the server in its browser. No additional app or cloud connection is required.
- Features
- Requirements
- Download and Install from GitHub
- Desktop App
- Connect Your Phone and Stop the Server
- Using a Personal Hotspot
- PowerPoint Permissions
- Using the Remote
- Configuration
- Network and Security
- Project Structure
- License
- Start and stop a presentation
- Move to the previous or next slide
- Turn the presentation screen black and restore it
- Display the current slide, total slide count, and elapsed time
- Display speaker notes on tablet-sized screens
- Display the connection and PowerPoint status
- Use touch, keyboard, or a Bluetooth clicker to control the presentation
- Protect the WebSocket control connection with a randomly generated session PIN by default
- Use a demo mode that simulates a presentation without PowerPoint
- Node.js 18 or later and npm
- Microsoft PowerPoint for actual presentation control
- The computer and mobile device must be connected to the same local network
- macOS or Windows for platform-specific PowerPoint control
PowerPointer can also run without PowerPoint in demo mode. On other operating systems, the server automatically uses this mode.
PowerPointer includes an optional Electron desktop app. It starts the server and opens a dashboard showing the PowerPoint status, current slide, connected clients, connection PIN, and local network addresses. Select an address to display its QR code, or copy it to the clipboard to open it on your phone.
Install the project dependencies as described below, then start the desktop app from the project folder:
npm run desktopYou do not need to run npm start separately; the desktop app starts the server for you. On macOS, closing the dashboard window leaves the server running; use Cmd+Q to quit the app and stop the server. On Windows, closing the window stops the app and server.
- Node.js 18 or later, including npm. Download and install the current LTS release from nodejs.org.
- Git, if you want to clone the repository using
git clone. Download it from git-scm.com. - Microsoft PowerPoint for actual presentation control.
- The computer and mobile device on the same local network.
After installation, check that Node.js and npm are available:
node --version
npm --versionBoth commands should print version numbers. If they do not, close and reopen the terminal. If the commands are still not found, check your Node.js installation.
-
Install Node.js 18 or later and Git (see above).
-
Open PowerShell.
-
Change to the folder where you want to keep the project, then clone the repository:
cd $HOME\Documents git clone https://github.com/MartHafner/PowerPointer.git cd PowerPointer
-
Install the exact project dependencies:
npm ci
-
Start the server:
npm start
-
Keep the PowerShell window open. The server prints one or more local addresses. Open one of them in your browser on your phone.
-
Install Node.js 18 or later. Git is often already available; if macOS prompts you, install the offered Xcode Command Line Tools.
-
Open Terminal.
-
Change to the folder where you want to keep the project, then clone the repository:
cd ~/Documents git clone https://github.com/MartHafner/PowerPointer.git cd PowerPointer
-
Install the project dependencies:
npm ci
-
Start the server:
npm start
-
Keep the Terminal window open. Open one of the local addresses printed by the server in your phone's browser.
You can download the project without installing Git:
-
Open the latest release of PowerPointer on GitHub.
-
Under Assets, download Source code (zip).
-
Extract the downloaded ZIP archive to a folder of your choice.
-
Open Terminal (macOS) or PowerShell (Windows) in the extracted project folder. This folder contains
package.json. -
Run the following commands:
npm ci npm start
The same commands work in PowerShell.
- Git: Run
git pullandnpm ciin the project folder, then restart the server. - ZIP: Download the latest release, extract it to a new folder, copy your
config/settings.jsonfrom the old folder, and runnpm ciandnpm start.
After startup, the computer prints the available network addresses and, if possible, a QR code in the terminal. Connect your phone and computer to the same local network, then open one of the printed addresses in your browser, for example http://192.168.1.23:8787.
macOS: If the page cannot be reached, allow node to accept incoming connections under System Settings → Network → Firewall → Options.
Stop the server by pressing Ctrl+C in the Terminal or PowerShell window where it is running.
If you are on an untrusted or shared network (for example, at a conference), you can use your phone's personal hotspot instead:
- On your iPhone, turn on Settings → Personal Hotspot.
- Connect the computer to your iPhone's Wi-Fi network.
- Start PowerPointer and open the address printed in the terminal in your iPhone's browser. The address usually starts with
172.20.10.when using an iPhone hotspot.
If the computer has several network connections, the terminal lists multiple addresses. Use the one that matches the hotspot network, because the QR code uses only the first address.
- macOS: Allow the application that launched Node.js (for example, Terminal) to control PowerPoint under System Settings → Privacy & Security → Automation.
- Windows: PowerPoint must be installed and running with a presentation open. PowerPointer connects to the running instance using PowerShell and COM automation.
Use the buttons to control the presentation. While it is running, the interface displays the current slide, the total number of slides, and elapsed time.
Keyboard shortcuts:
| Key | Action |
|---|---|
| Right arrow, Page Down, or Space | Next slide |
| Left arrow or Page Up | Previous slide |
b or . |
Turn the screen black or restore it |
The server checks PowerPoint's status every 500 milliseconds (twice per second) by default. If the connection is lost, the web interface automatically tries to reconnect.
Settings are stored in config/settings.json:
| Setting | Default | Description |
|---|---|---|
port |
8787 |
HTTP and WebSocket port |
host |
0.0.0.0 |
Network address the server listens on |
pin |
"auto" |
Generate a random four-digit PIN when the server starts; set to "" to disable PIN protection |
pollIntervalMs |
500 |
Interval between PowerPoint status checks, in milliseconds |
The generated PIN is printed in the server terminal and remains valid until the server stops. Set pin to a fixed value to use a custom PIN. PORT overrides the configured port; POWERPOINTER_PIN overrides the configured PIN, including with auto or an empty value. Example for PowerShell:
$env:POWERPOINTER_PIN = "1234"
npm startThe web interface prompts for the PIN when connecting. It is stored for the current browser tab session.
Demo mode simulates a presentation with ten slides. On macOS and Windows, enable it with the POWERPOINTER_MOCK environment variable:
POWERPOINTER_MOCK=1 npm startIn PowerShell:
$env:POWERPOINTER_MOCK = "1"
npm startThe npm run dev script enables the same mode in shells that support Unix-style environment variable assignment.
Debug logging adds timestamps and details about server startup and shutdown, TCP and HTTP connections, WebSocket connections and messages, and process warnings. To enable it on macOS or Linux, run:
DEBUG=1 npm startThe npm run debug script does the same on shells that support Unix-style environment variable assignment. In PowerShell, use:
$env:DEBUG = "1"
npm startDebug output appears in the same terminal as the server. HTTP and WebSocket URLs have their PIN masked, but WebSocket message contents are logged. Avoid sharing debug logs publicly; to return to normal logging in PowerShell, run Remove-Item Env:DEBUG before starting the server again.
The web interface and control connection are intended for use on a trusted local network. The server rejects connections from non-local IP addresses. The default PIN is random and changes each time the server starts, but it has only four digits and is displayed in the server terminal. To slow PIN guessing, five incorrect PIN attempts from the same client IP trigger a lockout. The first lockout lasts one minute; subsequent lockouts double in duration up to a maximum of 15 minutes. During a lockout, even the correct PIN is rejected. An attempt to connect without a PIN does not count as a failed attempt, and a successful connection resets the failed-attempt and lockout history for that IP. This rate limit is held in memory and resets when the server restarts.
A PIN protects the WebSocket control connection but does not encrypt it. By default, PowerPointer uses HTTP and WebSocket without TLS, so someone able to monitor local network traffic may capture the PIN and presentation data. Do not expose the server port to the public internet, and only use PowerPointer on networks you trust. Setting pin to an empty value disables PIN protection.
PowerPointer/
├── config/
│ └── settings.json
├── desktop/
│ ├── main.js
│ ├── panel.css
│ ├── panel.html
│ ├── panel.js
│ └── preload-panel.js
├── public/
│ ├── app.js
│ ├── index.html
│ └── style.css
├── server/
│ ├── platforms/
│ │ ├── macos.js
│ │ └── windows.js
│ ├── network.js
│ ├── debug.js
│ ├── pin.js
│ ├── ratelimit.js
│ ├── powerpoint.js
│ └── server.js
├── install.command
├── package.json
└── package-lock.json
server/server.jsserves the web interface and manages HTTP, WebSocket, and status connections.server/network.jsdiscovers local IPv4 addresses and checks whether a client is on a local network.server/debug.jsprovides optional timestamped logging whenDEBUGis enabled.server/pin.jsgenerates the random session PIN.server/ratelimit.jslimits repeated incorrect PIN attempts per client IP.server/powerpoint.jsprovides the shared command interface and demo mode.server/platforms/contains the PowerPoint integrations using AppleScript (macOS) and PowerShell/COM (Windows).desktop/contains the optional Electron app and its connection dashboard.public/contains the remote-control interface.config/settings.jsoncontains the server settings.install.commandis a macOS installation script.
This project is licensed under the MIT License.


