Skip to content
overterm
Documentation

Simulator

The iOS simulator's live screen beside the terminal, with no Screen Recording permission involved.

The phone button in the title bar puts an iOS simulator in the column the browser uses. It is the simulator, not a picture of one: the screen is live, and clicks, drags, the wheel and the keyboard go to the device.

The button only appears when Settings ▸ Browser has the column enabled, and the pane needs Xcode with at least one simulator. Pressing the phone while the simulator already shows closes the column; pressing the globe takes the column back for the browser. See Panes and Tab Peek for why the two share one slot.

Why there is no permission prompt

The picture is the device’s own framebuffer. Overterm reads the simulator’s IOSurface out of CoreSimulator and puts it straight into a layer: no capture, no copy, no encoding — and nothing of the Mac’s screen is read, so no Screen Recording grant is involved and macOS never asks.

CoreSimulator reports when it has drawn, and the layer is told to look again; a rotation or a resize arrives as a new surface. There is no polling on this path at all.

How it talks to the device

There is no public API for any of this. simctl boots a device and takes screenshots, and that is the whole of it. So, like every tool that puts a simulator in its own window, Overterm loads this Mac’s CoreSimulator and Xcode’s SimulatorKit at runtime and uses what Simulator.app uses. Nothing is bundled, nothing is linked at build time, and every step is allowed to fail — a missing class is an empty pane, not a crash at launch.

Input uses SimulatorKit’s own event builders, the same C functions Simulator.app’s window calls when you click in it, carried to the device by CoreSimulator’s HID client. The wire format is never written here, only asked for.

Gesture What is sent
click a touch down, then up a moment later
drag down, moved, up — a finger lifted outside the picture still lifts
scroll wheel a swipe that ends shortly after the last wheel event
keyboard the key code straight through
the toolbar’s Home button the device’s own Home button, so it works on a body that has not had one since the iPhone X

A touch is addressed as a ratio of the screen, 0 to 1 from the top left, so it is correct whatever size the column is.

When the device ignores it

From Xcode 27 (CoreSimulator 1155.4) the guest drops this kind of input for the whole boot: the bytes arrive, correctly, and nothing happens — which is worse than refusing. Overterm compares the CoreSimulator version numerically and, when that is the case, says so in the pane:

This simulator ignores taps from other apps.

with a button that opens Simulator.app, where taps do work. The Home button and the cursor follow the same answer, rather than leaving you tapping at a picture. A live picture is not the same thing as a usable one: the screen can arrive perfectly from a device that refuses the input client.

The fallback

Without Xcode’s simulator frameworks — not installed, or an Xcode that moved them — the pane falls back to xcrun simctl io <device> screenshot, a BMP several times a second, downsampled to the pane off the main thread. It is a picture, not a simulator you can use, and the pane says so:

Xcode’s simulator frameworks aren’t here: a screenshot every half second, and no taps.

Never a blank pane, in other words. BMP rather than PNG because simctl spends most of a screenshot’s time encoding the PNG and this pane throws the pixels away anyway.

The device picker

The picker in the toolbar lists what xcrun simctl list devices --json reports: booted devices first, then the newest runtime, each runtime’s devices together, then by name. A device reads as “iPhone 17 Pro — iOS 26.2”, and booted ones are marked.

Choosing a device that is shut down boots it with xcrun simctl boot — not by launching Simulator.app, which this pane does not need. The pane says “Booting …” while it does.

The list is re-read every three seconds while the pane is up, so a simulator you booted elsewhere appears without being asked for.

The states you may see:

Pane says Means
“No simulators on this Mac. They come with Xcode.” no devices at all
“No simulator is running.” with Boot … devices listed, none booted
“Waiting for the simulator’s screen…” booted, no surface yet
“This simulator ignores taps from other apps.” live, but input is dropped by the guest

The menu also says “No simulators — Xcode isn’t installed” when there is nothing to pick.

Costs nothing while it is shut

The surface and its callbacks go when the column is collapsed or the browser takes it back — the same rule the inbox, Overgit and the usage pane keep. A stream costs; shut, it costs nothing.