An open-source Screen Studio clone for macOS, built with Tauri 2 + React 19 + TypeScript.
Real, in-process screen capture via ScreenCaptureKit — plus webcam, microphone, and system-audio recording — with a polished editor: auto-zoom-on-click, cursor overlay, wallpaper backgrounds, a camera bubble, multi-track audio, and export to mp4 / gif. macOS only.
Download the latest .dmg from Releases, open it, and drag the app to Applications.
Important
Release builds are not notarized by Apple (this is a free open-source project without a paid Apple Developer account), so on first launch macOS will say the app "cannot be opened because Apple cannot check it for malicious software." To open it:
- Right-click (or Control-click) the app → Open → Open again in the dialog, or
- after the first blocked attempt, go to System Settings → Privacy & Security and click Open Anyway.
You only need to do this once; afterwards it launches normally.
If you grant Screen Recording / Accessibility but the app keeps showing the onboarding screen and never recognizes the grant, it's a macOS code-signing quirk, not a bug:
- Move the app into
/Applicationsvia Finder — don't run it straight from the.dmgor Downloads. Doing so triggers Gatekeeper "App Translocation", which launches the app from a random read-only path, so the permission grant never matches the next launch. - Remove the quarantine flag:
xattr -dr com.apple.quarantine "/Applications/OpenScreen Studio.app" - Launch from
/Applications, then grant both permissions. If it still won't recognize them, reset the entries once and re-grant:tccutil reset ScreenCapture org.glyphsoftware.oss tccutil reset Accessibility org.glyphsoftware.oss
Builds produced with bun run build:signed (see Build) carry a stable self-signed identity, which is what lets TCC pin the grant — without it (plain ad-hoc builds) permissions can fail to persist even after steps 1–2.
bun install # installs JS deps; postinstall fetches bundled ffmpeg binaries
bun run tauri dev # run the desktop app (frontend + Rust)Warning
The screen recording does not work while running in dev mode.
This project uses Bun. Never use
npm/npx/pnpm/yarn— usebunx <bin>andbun run <script>.
On first launch, if Screen Recording or Accessibility permissions are missing, an onboarding window appears. Grant both in System Settings → Privacy & Security (Accessibility is needed for cursor/click tracking). Otherwise the Capture HUD opens — pick a display / window / area, then record. Recording finishes into the editor.
bun run tauri build # produces .app + .dmg in src-tauri/target/release/bundle/ (ad-hoc signed)
bun run build:signed # same, but signed with a stable self-signed identity (recommended for release)
bun run build # frontend-only build (tsc && vite build)
bunx tsc --noEmit # type-checkFor Rust: cd src-tauri && cargo check / cargo clippy.
The bundle ships entitlements.plist (camera / audio-input / screen-capture) and usage strings in Info.plist. Requires macOS 13+ (the ScreenCaptureKit recording path needs macOS 15+).
Without a paid Apple account we can't notarize, but we can still produce a stable code signature — which is what macOS TCC needs so Screen Recording / Accessibility grants persist across launches on other Macs (a plain ad-hoc tauri build has no stable Designated Requirement and the grants can fail to stick).
bun run build:signed runs scripts/sign-cert.sh (idempotent — creates a self-signed "OpenScreen Studio Self-Signed" code-signing identity in your login keychain on first run), then builds with APPLE_SIGNING_IDENTITY set so Tauri signs the .app and the bundled ffmpeg. The first build may prompt once for keychain access — click Always Allow.
This does not remove the Gatekeeper "unidentified developer" warning for end users (that still requires Apple notarization / a $99 Developer account, or a nonprofit/edu fee waiver). It only fixes permission persistence.
The .dmgs on Releases are built by .github/workflows/release.yml on a v* tag push. It signs via tauri-action when these repo secrets are present (otherwise it degrades to an ad-hoc build with green CI):
| Secret | Value |
|---|---|
APPLE_CERTIFICATE |
base64 of a legacy-format .p12 holding the self-signed code-signing identity |
APPLE_CERTIFICATE_PASSWORD |
the .p12 export password |
APPLE_SIGNING_IDENTITY |
OpenScreen Studio Self-Signed (must match the cert CN) |
All CI releases share this one stored identity, so the Designated Requirement is stable across versions and TCC grants persist for end users. To rotate/recreate it, generate a fresh self-signed cert as a legacy .p12 (macOS's security import can't read OpenSSL 3's default format):
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
-keyout key.pem -out cert.pem -subj "/CN=OpenScreen Studio Self-Signed" \
-addext "keyUsage=critical,digitalSignature" \
-addext "extendedKeyUsage=critical,codeSigning"
openssl pkcs12 -export -legacy -inkey key.pem -in cert.pem -out ci.p12 -passout pass:PASSWORD
base64 -i ci.p12 | gh secret set APPLE_CERTIFICATE
printf 'PASSWORD' | gh secret set APPLE_CERTIFICATE_PASSWORD
printf 'OpenScreen Studio Self-Signed' | gh secret set APPLE_SIGNING_IDENTITYRotating the cert changes the Designated Requirement, so existing users must re-grant Screen Recording / Accessibility once after upgrading to the first build signed by the new cert.
- Screen recording: ScreenCaptureKit, entirely in-process via the
screencapturekitcrate. AnSCStream+SCRecordingOutputwrites mp4 directly — no ffmpeg sidecar in the recording path. Supports display, window, and cropped-area capture, plus pause / resume / restart / cancel. - Webcam sidecar. The selected camera records to a sidecar QuickTime movie via AVFoundation (
AVCaptureSession+AVCaptureMovieFileOutput, hardware-encoded), on its own thread. The editor composites it as a camera bubble; its pause/resume mirrors the screen recording's segment concat. Seecamera.rs. - System + microphone audio. ScreenCaptureKit delivers system audio and mic audio (macOS 15+) as separate streams on the same
SCStream; each is written to a WAV sidecar, anchored to the first video frame's timestamp so the tracks stay in sync, giving the editor independently editable audio tracks. Seeaudio_tap.rs. - Audio source enumeration parses
ffmpeg -f avfoundation -list_devices. - Cursor sidecar. During recording a
CursorTrackrecords cursor position, clicks, and cursor-shape transitions, then writes a<recording>.cursor.jsonnext to the mp4. The editor consumes this for auto-zoom-on-click and the cursor overlay. - Mic metering:
cpalsamples the default input and emits peak amplitude asmic-levelevents at ~30 Hz. - Export. An offline pipeline steps the recording frame-by-frame, composites screen + camera + background on WebGL2 (Canvas2D fallback), and encodes to mp4 or gif — to a file or the clipboard. See
exporter.ts.
Recordings land in ~/Movies/OpenScreen Studio/OpenScreen-<timestamp>-<uuid>.mp4, alongside their sidecars: .cursor.json, the camera QuickTime movie, and the system / mic audio WAVs.
ffmpeg is bundled, not a $PATH dependency. scripts/fetch-ffmpeg.sh runs on postinstall and downloads src-tauri/binaries/ffmpeg-{aarch64,x86_64}-apple-darwin, used only for audio-device enumeration.
There is no single React state machine — App.tsx routes purely by the native window label:
- permissions — onboarding for screen-recording + accessibility grants.
- hud — small frameless always-on-top bar (
idle | countdown | recording). - editor (1440×900) — the full editor; hidden until a recording finishes.
- picker-* — transparent per-display overlays for picking a display / window / drag-area.
src/
App.tsx routes by window label: editor | permissions | picker-* | hud
components/
CaptureHUD.tsx pre-record HUD (source, webcam/mic/system pills, record btn)
Permissions.tsx onboarding grant flow
PickerOverlay.tsx per-display overlay: pick display / window / drag an area
Editor/index.tsx full editor (~3200 lines): viewport, inspector, timeline,
auto-zoom, cursor overlay, save/open
hooks/ useAccent, useTheme
lib/
native.ts typed Tauri command wrappers + listen helpers + sidecar types
autoZoom.ts derive zoom segments from cursor-sidecar clicks
styles/ globals.css + tokens.css (design system, ported from handoff)
src-tauri/
src/lib.rs ~2500 lines: SCK capture, picker, cursor sidecar, ~37 #[command]s
src/main.rs thin entry; handles --probe-screen-recording subprocess
tauri.conf.json window config + asset-protocol scope + externalBin ffmpeg
Info.plist camera / microphone / screen-capture usage strings
entitlements.plist camera / audio-input / screen-capture
scripts/fetch-ffmpeg.sh downloads the platform ffmpeg binaries (run on postinstall)
See AGENTS.md for deeper architecture notes.
Shipped:
- ✅ Webcam capture and compositing.
- ✅ System-audio capture.
- ✅ Real export pipeline — offline frame-by-frame compositing to mp4 / gif, to file or clipboard.
- ✅ Timeline editing with per-track audio (mic / system) and auto-zoom segments.
Planned:
- Richer timeline effects (transitions, multi-clip trimming).
- Apple notarization for friction-free installs.
Contributions are welcome — bug reports, docs, UI polish, and features. See CONTRIBUTION.md for prerequisites, setup, conventions, and the pull-request checklist. For deeper architecture notes, see AGENTS.md.
Built and maintained by Glyph Software LLP — Crafting Scalable Solutions for Modern Needs. We build AI-powered and custom software: web/mobile, cloud infrastructure, data analytics, and generative AI systems, for startups and enterprises. Based in Bengaluru, India.
- Website: glyphsoftware.org
- Email: contact@glyphsoftware.org
- GitHub: Glyph-Software
- LinkedIn: Glyph Software
- Hugging Face: glyphsoftware