Real-time typographic portrait — your webcam feed rendered as a mosaic of colored pill-shaped word badges.
Typoface captures your webcam stream and renders it as a dense grid of rounded Korean (or multi-language) word badges on a canvas. Each pill's opacity is computed from the local pixel brightness of the video frame — bright areas of your face produce opaque, vivid pills; shadows fade into the background. The result is a living, breathing typographic portrait.
All processing happens on-device, in your browser. No data is sent anywhere.
- 🎵 Audio Reactive Mode — AnalyserNode on your mic drives bass → pulse amplitude and mid → brightness
- 🌍 Multi-language Word Pools — Korean, Japanese, Arabic, English, Spanish, or fully custom text
- 🎨 Named Color Themes — K-Pop, Matrix, Sakura, Ocean, Fire, Neon, Mono, Pastel (8 total)
- 🌊 Visual Effects — Wave (sine ripple), Glitch (band shift), Breathe (sync pulse), or None
- ⏱ Countdown Capture — 3-2-1 animated overlay for hands-free snapshots
- 📷 PNG Capture — Save the current frame as a high-res PNG
- ⏺ WebM Recording — Record a video clip with one click
- ✏️ Custom Text — Type your own words; they replace the word pool live
- ⌨️ Keyboard Shortcuts — M, I, C, R, Space
- ⚡ 60fps Canvas — Fully optimized render loop with pre-allocated Float32Array luminance buffers
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| Language | TypeScript 5 |
| Styling | Tailwind CSS 3 |
| Canvas | Web Canvas API |
| Camera | getUserMedia |
| Audio | Web Audio API — AnalyserNode |
| Font | Noto Sans KR (Google Fonts) |
| Recording | MediaRecorder API |
# 1. Clone the repo
git clone https://github.com/victorgalvez56/typoface.git
cd typoface
# 2. Install dependencies
npm install
# 3. Start the dev server
npm run dev
# 4. Open http://localhost:3000| Control | Description |
|---|---|
| Mirror | Flip the canvas horizontally (selfie mode) |
| Invert | Invert the luminance map (dark face = lit pills) |
| Contrast | Low / Normal / High / Extreme |
| Density | Normal / Dense / Micro pill sizes |
| FX | Cycle Wave → Glitch → Breathe → None |
| Audio | Toggle mic-reactive pulse |
| Theme | K-Pop, Matrix, Sakura, Ocean, Fire, Neon, Mono, Pastel |
| Random | Randomize to a new theme |
| Language | 🇰🇷 Korean, 🇯🇵 Japanese, 🇸🇦 Arabic, 🇺🇸 English, 🇪🇸 Spanish, ✏️ Custom |
| Capture | Download PNG snapshot |
| Timer | 3-2-1 countdown then capture |
| Record | Start/stop WebM recording |
| Key | Action |
|---|---|
M |
Toggle mirror |
I |
Toggle invert |
C |
Capture PNG |
R |
Start / Stop recording |
Space |
Randomize color theme |
getUserMediafeeds into a hidden<video>element- Each frame, the video is drawn to an off-screen canvas with CSS contrast filter applied
computeLumBuffersreads the raw RGBA pixels and builds:lumBuf: BT.601 luminance per pixelblurBuf: 22×22-pixel block means for unsharp masking
- For each pill,
getLum(cx, cy)returns the enhanced luminance:lum + (lum - blockMean) * 1.6 - Alpha is computed as
pow((lum - threshold) / (1-threshold), 0.75) - A spring-like per-pill sine pulse modulates alpha and scale
- Audio bass multiplies pulse amplitude; mid adds brightness
- Visual effects (Wave, Glitch, Breathe) modify positions and phases
- Pills are drawn with
ctx.roundRect+ text overlay
Contributions are welcome! Please open an issue or submit a pull request.
- Fork the repository
- Create your feature branch:
git checkout -b feat/amazing-feature - Commit your changes:
git commit -m 'feat: add amazing feature' - Push to the branch:
git push origin feat/amazing-feature - Open a pull request
MIT — see LICENSE for details.
Made with care by victorgalvez56