PixelStream-BLD / README.md
Abhisingh-18's picture
Mirror of github.com/Abhisingh18/PixelStream-BLD
0266b68 verified
|
Raw
History Blame Contribute Delete
5.32 kB
# PixelStream πŸ–₯️➑️🌐
A mini "TeamViewer for a browser". You open a web UI, hit **Start Browser**, and a
**headless Chromium running inside a Docker container** streams its screen back to
your browser in real time. You can **click, scroll, type, and navigate** β€” and it
all happens inside that remote headless browser...........
---
## How it works
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” click / scroll / type (WebSocket) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” CDP β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Web UI β”‚ ───────────────────────────────────► β”‚ Node backend β”‚ ───────► β”‚ Headless Chromium β”‚
β”‚ (Next.js) β”‚ β”‚ (ws + CDP) β”‚ β”‚ (Puppeteer) β”‚
β”‚ <canvas> β”‚ ◄─────────────────────────────────── β”‚ β”‚ ◄─────── β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ live JPEG frames (WebSocket) β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ screencast β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
- **Frontend** (`/frontend`) β€” Next.js app. A `<canvas>` paints the live frames;
mouse/keyboard/scroll events are captured, converted to real browser
coordinates, and sent over a WebSocket.
- **Backend** (`/backend`) β€” Node.js + `ws` + Puppeteer. Launches Chromium, uses the
**Chrome DevTools Protocol (CDP)** `Page.startScreencast` to get a continuous
stream of JPEG frames, and injects input via `Input.dispatchMouseEvent` /
`Input.dispatchKeyEvent`.
- **Docker** β€” both services run in containers via `docker compose`. The backend
uses the official Puppeteer image (Chromium + system deps preinstalled).
### Why CDP screencast (not a screenshot loop)?
`Page.startScreencast` only emits a frame when the page actually changes, and it's
much smoother and lower-latency than taking `page.screenshot()` on a timer.
---
## Run it
### Option A β€” Docker (recommended)
```bash
docker compose up --build
```
Then open **http://localhost:3000** and click **Start Browser**.
### Option B β€” Local (no Docker, for fast iteration)
```bash
# terminal 1
cd backend && npm install && npm start # ws server on :8080
# terminal 2
cd frontend && npm install && npm run dev # UI on :3000
```
---
## Deploy (Frontend β†’ Vercel, Backend β†’ Render)
> ⚠️ The browser page is served over **HTTPS** (Vercel), so it can only open a
> **secure** WebSocket (`wss://`). Render gives you an `https://…onrender.com`
> URL, whose WebSocket endpoint is `wss://…onrender.com`. Plain `ws://` will be
> blocked as mixed content.
### 1. Backend on Render
- New **Web Service** β†’ connect this repo.
- Runtime: **Docker**, Dockerfile path: `backend/Dockerfile`, context: `backend`
(or just use the included `render.yaml` Blueprint).
- Deploy. Note the URL, e.g. `https://pixelstream-backend.onrender.com`.
- Render injects `PORT` automatically β€” the server already reads it.
### 2. Frontend on Vercel
- New Project β†’ import this repo β†’ set **Root Directory = `frontend`**.
- Add an environment variable:
| Key | Value |
|-----|-------|
| `NEXT_PUBLIC_WS_URL` | `wss://pixelstream-backend.onrender.com` |
- Deploy. Open the Vercel URL β†’ **Start Browser**.
---
## What works βœ…
- Start a headless Chromium in a Docker container from the web UI
- Live screen streaming via CDP screencast (JPEG frames over WebSocket)
- Mouse: move, left/right click, scroll
- Keyboard: printable characters + common special keys (Enter, Backspace, Tab,
arrows, Esc, Delete…)
- URL bar to navigate the remote browser
- Accurate click mapping (canvas coords β†’ real viewport coords)
## Known limitations / where it gets hard ⚠️
- **Keyboard coverage** β€” only common special keys are mapped; modifier
combos (Ctrl+C, Shift+selection) aren't fully wired yet.
- **Single session** β€” one browser per server; no multi-user / multi-tab.
- **Streaming** β€” JPEG-over-WebSocket is simple but bandwidth-heavy; WebRTC or
VP8/H.264 encoding would be smoother at scale.
- **Chromium-in-Docker** β€” needs `--no-sandbox`, `--disable-dev-shm-usage`, and
`shm_size: 1gb` or Chromium crashes. (These are already set.)
## Next steps πŸš€
1. Full keyboard model with modifiers + IME/composition events
2. Multiple isolated sessions (one container per user, spawned on demand)
3. WebRTC streaming for lower latency / adaptive quality
4. Reconnect handling + session timeouts + resource cleanup
---
## Project structure
```
Pixel/
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ backend/
β”‚ β”œβ”€β”€ Dockerfile
β”‚ β”œβ”€β”€ package.json
β”‚ └── server.js # ws server + Puppeteer + CDP screencast/input
└── frontend/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ package.json
β”œβ”€β”€ next.config.js
└── app/
β”œβ”€β”€ layout.js
└── page.js # UI + canvas + input capture
```