Views
No views yet
┌──────────────┐ click / scroll / type (WebSocket) ┌───────────────┐ CDP ┌──────────────────┐
│ Web UI │ ───────────────────────────────────► │ Node backend │ ───────► │ Headless Chromium │
│ (Next.js) │ │ (ws + CDP) │ │ (Puppeteer) │
│ <canvas> │ ◄─────────────────────────────────── │ │ ◄─────── │ │
└──────────────┘ live JPEG frames (WebSocket) └───────────────┘ screencast └──────────────────┘/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) — 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 compose. The backend
uses the official Puppeteer image (Chromium + system deps preinstalled).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.docker compose up --build1# terminal 1
2cd backend && npm install && npm start # ws server on :8080
3
4# terminal 2
5cd frontend && npm install && npm run dev # UI on :3000⚠️ The browser page is served over HTTPS (Vercel), so it can only open a secure WebSocket (wss://). Render gives you anhttps://…onrender.comURL, whose WebSocket endpoint iswss://…onrender.com. Plainws://will be blocked as mixed content.
backend/Dockerfile, context: backend
(or just use the included render.yaml Blueprint).https://pixelstream-backend.onrender.com.PORT automatically — the server already reads it.frontend.| Key | Value |
|---|---|
NEXT_PUBLIC_WS_URL | wss://pixelstream-backend.onrender.com |
--no-sandbox, --disable-dev-shm-usage, and
shm_size: 1gb or Chromium crashes. (These are already set.)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