Realtime / Computer Vision

SulyapPB

Photobooths need two people in one place. This one doesn't.

DisclaimerLive peer-to-peer video is not enabled in the public demo: it needs a paid TURN relay. I'm planning to use Cloudflare, but I haven't set it up yet.

SulyapPB screenshot
SulyapPB screenshot 2
SulyapPB screenshot 3
SulyapPB poster

A photobooth for two people who are nowhere near each other. One person makes a room, sends the 6-character code to their partner, and both phones count down together. You snap on yours, they snap on theirs, and one classic 2×6 photo strip comes out with both of you on it.

Core
  • Next.js 15: App Router, Turbopack
  • React 19
  • TypeScript, strict
  • ESLint 9 with eslint-config-next
Styling
  • Tailwind CSS v4 via @tailwindcss/postcss
  • clsx + tailwind-merge for class composition
  • Hand-rolled keyframes in globals.css: rise, tick, float
Graphics & motion
  • @mediapipe/tasks-vision: selfie segmentation, cutting the person out at 256×256, running as a module-level singleton so one model and GPU context serves the preview, the capture, and the peer stream
  • Canvas 2D compositor: mask, paint backdrop, person on top, producing a canvas that stands in for the camera everywhere the camera used to be read
  • Backdrops are painted gradients rather than photos - free to download, sharp at any size, and forgiving of the hair-edge artifacts no segmenter gets exactly right
  • Full graceful degradation: if the model won't load, the WASM won't compile, or the phone's too slow, you land back on the raw camera, which is still a working photobooth
Backend & data
  • Supabase Realtime (broadcast only) as the room transport, swapping in automatically the moment the two NEXT_PUBLIC_SUPABASE_* vars exist
  • BroadcastChannel fallback transport for single-device and cross-tab dev, so the whole booth was testable before any backend existed. The booth talks to one RoomTransport interface and never learns which it got.
  • Supabase Postgres with a service-role client for the licenses table only: RLS-free, server-only, with a runtime throw if it is ever imported in a browser
  • PayMongo for premium (GCash, card, PayMaya, GrabPay) at ₱149. Codes are minted in the signature-verified webhook, never at checkout.
  • Resend for the feedback form, with a mailto fallback when unkeyed
  • In-memory per-IP throttling on the checkout and feedback routes
Deploy
  • Vercel
NextPortfolio Website