npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

serve-emul

v0.0.4

Published

The `npx serve` of Android devices — stream a booted emulator or attached device over a WebSocket H.264 feed decoded in the browser with WebCodecs.

Readme

serve-emul

The npx serve of Android devices.

Host your Android emulator (or real device) for use with agent tools like Codex, Cursor, or Claude Desktop — locally, over your LAN, or tunnel anywhere.

bunx serve-emul@latest
# or: npx serve-emul@latest
# → Preview at http://localhost:3300

Use @latest for one-off runs so Bun/npm fetches the newest published version instead of reusing a cached or locally installed copy.

serve-emul spawns the scrcpy server on the device, opens an adb forward tunnel, pipes H.264 frames over a WebSocket, and decodes them in the browser with WebCodecs. Input events flow back over the same socket to scrcpy's control channel.

Package Rename

The npm package name is serve-emul. npm package names cannot be renamed in place, so releases under this name should be published as a new package:

npm publish --workspace packages/serve-emul
npm deprecate serve-emu "Package renamed to serve-emul. Use: npm install serve-emul"

Status

Current package version: see package.json and CHANGELOG.md.

Working:

  • Live H.264 video stream from device → WebCodecs canvas
  • Taps, swipes, hardware buttons (Back / Home / Recents / Power)
  • Text injection, keyevents
  • Multi-client (multiple browser tabs share one stream)
  • Auto-replay of SPS/PPS to clients joining mid-stream
  • Emulator GPS location control from the browser UI and POST /api/location
  • Route playback from GPX, GeoJSON, KML, or waypoint JSON
  • Logcat forwarding over SSE with browser-side filter, pause, and copy controls
  • Network on/off control from the browser UI and POST /api/network
  • Agent-friendly REST input APIs plus session event replay
  • App management controls for APK install, launch, clear data, force stop, and permission grants

Planned:

  • Multi-device routing
  • Embeddable Connect-style middleware (serve-emul/middleware)
  • Compiled single binary

Requirements

  • Node.js 18+ or Bun 1.1+
  • adb on PATH (Android platform-tools)
  • A booted device/emulator (adb devices shows it), or an AVD name passed with --avd
  • Chrome / Edge / Safari 16.4+ (for WebCodecs)

Quick start

bun install
bun run --filter serve-emul setup    # downloads scrcpy-server-v4.0 into vendor/
bun run packages/serve-emul/src/cli.ts
# → http://localhost:3300

The setup step is also run lazily on first start, so you can skip it.

CLI

serve-emul [-p <port>] [-s <serial>] [--max-fps N] [--bit-rate N] [--max-size N] [--key-frame-interval sec]
serve-emul --avd <name> [--restart-avd]
serve-emul --avd-list
serve-emul --running-avds

| flag | default | meaning | |---|---|---| | -p, --port | 3300 | HTTP port for the preview server | | -s, --serial | auto | adb device serial (only required when multiple devices are attached) | | --max-fps | 60 | cap source frame rate | | --bit-rate | 8000000 | H.264 bit rate in bps | | --max-size | 1920 | downscale longest edge to N pixels; 0 = native (encoders on many emulators reject above ~2560, so the default trims) | | --key-frame-interval | 1 | ask the encoder for regular keyframes so clients can recover without resetting video capture; 0 disables this codec option | | --avd | none | launch this Android Virtual Device before streaming | | --restart-avd | false | stop a running matching AVD before launching it | | --avd-list | false | list available Android Virtual Device names | | --running-avds | false | list currently running emulator serials and AVD names | | --emulator | auto | Android Emulator binary path; defaults to PATH or Android SDK env vars | | --emulator-port | auto | emulator console port for --avd; must be an even port from 5554 through 5682 |

HTTP API

Set an Android Emulator GPS fix:

curl -X POST http://localhost:3300/api/location \
  -H 'Content-Type: application/json' \
  -d '{"latitude":37.5665,"longitude":126.978}'

Location control uses the Android Emulator geo fix command and is currently emulator-only.

Start route playback from waypoints:

curl -X POST http://localhost:3300/api/route \
  -H 'Content-Type: application/json' \
  -d '{"speedKph":30,"multiplier":1,"loop":false,"waypoints":[{"latitude":37.5665,"longitude":126.978},{"latitude":37.5651,"longitude":126.98955}]}'

Pause, resume, or stop playback:

curl -X POST http://localhost:3300/api/route/control \
  -H 'Content-Type: application/json' \
  -d '{"action":"pause"}'

Drive the device with REST:

curl -X POST http://localhost:3300/api/tap \
  -H 'Content-Type: application/json' \
  -d '{"x":0.5,"y":0.5}'

curl -X POST http://localhost:3300/api/text \
  -H 'Content-Type: application/json' \
  -d '{"text":"hello"}'

curl http://localhost:3300/api/screenshot --output screen.png

Stream logcat over SSE:

curl -N 'http://localhost:3300/api/logcat?package=com.example.app&search=error'

Toggle device network:

curl http://localhost:3300/api/network

curl -X POST http://localhost:3300/api/network \
  -H 'Content-Type: application/json' \
  -d '{"enabled":false}'

Replay recorded input and location events:

curl -X POST http://localhost:3300/api/session/replay \
  -H 'Content-Type: application/json' \
  -d '{"multiplier":2}'

Manage apps:

curl -X POST http://localhost:3300/api/apps/install \
  -F apk=@/path/to/app.apk

curl -X POST http://localhost:3300/api/apps/launch \
  -H 'Content-Type: application/json' \
  -d '{"packageName":"com.example.app","activity":".MainActivity"}'

curl -X POST http://localhost:3300/api/apps/clear \
  -H 'Content-Type: application/json' \
  -d '{"packageName":"com.example.app"}'

curl -X POST http://localhost:3300/api/apps/grant \
  -H 'Content-Type: application/json' \
  -d '{"packageName":"com.example.app","permission":"android.permission.POST_NOTIFICATIONS"}'

How it works

┌──────────────────┐ adb forward  ┌─────────────┐  H264 / WS    ┌─────────┐
│ scrcpy-server.jar│ ◄──────────► │  serve-emul  │ ────────────► │ Browser │
│ on device        │  TCP tunnel  │   (Bun)     │   WebCodecs   │ <canvas>│
│  • video socket  │              │             │ ◄──────────── │         │
│  • control socket│              │             │  input JSON   │         │
└──────────────────┘              └─────────────┘               └─────────┘
  1. The CLI pushes scrcpy-server-v4.0 to /data/local/tmp/scrcpy-server.jar.
  2. It opens adb forward tcp:<localPort> localabstract:scrcpy_<scid>.
  3. It spawns app_process with the scrcpy server class on the device, then connects two sockets through the tunnel: video and control.
  4. The Bun server reads scrcpy's framed H.264 stream (12-byte header + Annex-B payload) and forwards each Access Unit as a binary WebSocket message. Raw /ws clients receive the Annex-B payload unchanged; the built-in browser UI opts into a 16-byte frame metadata header with keyframe and PTS data.
  5. The browser configures a VideoDecoder from the SPS, uses server-provided frame metadata to avoid per-frame NAL scans, and draws frames to a <canvas>. Pointer events are normalized to device coordinates and written back to scrcpy's control socket as 32-byte touch packets.

License

Apache-2.0. Bundles the upstream scrcpy server binary (Apache-2.0) at runtime.