Ultra-lightweight screen recorder built with Tauri 2 + Rust + SolidJS.
Cross-platform: Windows, macOS, Linux. ~5MB bundle size.
- Visual Studio C++ Build Tools
- WebView2 (pre-installed on Windows 10/11)
# Install via winget
winget install Rustlang.Rustup
winget install Gyan.FFmpeg
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget \
libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev \
ffmpeg pipewire libpipewire-0.3-dev
# Install Node dependencies
npm install
# Install Tauri CLI
cargo install tauri-cli@^2
# Run in development mode
cargo tauri dev
# Build for production
cargo tauri build
tapeit/
├── src/ # SolidJS frontend
│ ├── components/
│ │ ├── recorder/ # Main window UI components
│ │ └── overlay/ # Floating overlay controls
│ ├── stores/ # State management (Solid signals)
│ ├── styles/ # CSS
│ └── utils/
├── src-tauri/ # Rust backend (Tauri 2)
│ └── src/
│ ├── capture/ # Screen capture engine (scap)
│ ├── audio/ # Audio capture (cpal)
│ ├── encoder/ # Streaming video encoder (FFmpeg)
│ ├── commands/ # Tauri IPC commands
│ └── utils/
├── package.json
└── vite.config.ts
| Layer |
Technology |
Why |
| Desktop Shell |
Tauri 2 |
~5MB bundle, native WebView, Rust backend |
| Recording Engine |
Rust + scap |
Cross-platform screen capture via native APIs |
| Audio |
cpal |
Cross-platform audio capture (WASAPI / CoreAudio / PulseAudio) |
| Encoding |
FFmpeg (CLI) |
H.264 video + AAC audio encoding |
| Frontend |
SolidJS |
Tiny bundle, fine-grained reactivity |
- Screen capture (displays + windows) via native APIs
- Streaming encoder — frames piped to FFmpeg in real-time (no in-memory accumulation)
- Mic + system audio capture with separate buffer mixing and AAC encoding
- Audio/video sync — automatic trimming of leading audio samples to align with video start
- Adjustable FPS (15 / 24 / 30 / 60)
- Pause / resume recording
- Floating overlay window (timer + controls, always-on-top, drag via timer region)
- Auto minimize/restore main window during recording
- MP4 output with timestamp naming (
tapeit_YYYYMMDD_HHMMSS.mp4)
- "Saved" banner with output path shown after recording completes
- Background error surfacing via
get_last_error polling
- Global shortcut
Ctrl+Shift+R — toggle recording start/stop from anywhere
- Streaming encode pipeline: Raw BGRA frames are piped directly to an FFmpeg stdin process during capture, eliminating memory buildup for long recordings.
- Separate audio buffers: System audio and mic audio are captured into independent buffers and mixed at mux time via
mix_and_trim(), with zero-padding for length differences and clamping to [-1.0, 1.0].
- Timestamp-based A/V sync: The recorder tracks
video_start_instant and computes a delta against the audio stream's start time to trim leading audio samples before muxing.
- Capability-based permissions: Window permissions (dragging, minimize, focus) and plugin access (global shortcuts, dialog, fs, shell) are explicitly declared in
capabilities/default.json.
- Event-driven state: Backend emits
recording-stopped and recording-saved events; the frontend store listens and updates reactive signals accordingly.
| Command |
Purpose |
get_capture_sources() |
List available displays and windows |
start_recording(config) |
Begin capture with source, fps, output dir |
stop_recording() |
Stop capture and encode to MP4 |
pause_recording() |
Pause frame capture |
resume_recording() |
Resume frame capture |
get_recording_state() |
Poll current recorder state |
get_last_error() |
Retrieve background thread errors |
show_overlay() |
Create and show floating overlay window |
hide_overlay() |
Close overlay window |
minimize_main() |
Minimize main config window |
restore_main() |
Restore and focus main window |
| Shortcut |
Action |
Ctrl+Shift+R |
Toggle recording start/stop |
Ctrl+Shift+S |
Take screenshot (not yet implemented) |