OpenScreen is a free, open-source screen recorder and video editor (Electron + React + TypeScript + Pixi.js) maintained as a continuation of the original v1.5.0 release. This file is the canonical guide for any AI coding agent working in this repo.
- Install deps:
npm install(Node 22.22.1, npm 10.9.4 — seepackage.json#engines) - Start dev:
npm run dev(Vite dev server; Electron window opens viavite-plugin-electron) - Build:
npm run build(TypeScript check + Vite build + electron-builder) - Typecheck:
npx tsc --noEmit(CI runs this; no standalone script) - Test (unit):
npm run test(Vitest, jsdom env) - Test (browser):
npm run test:browser(Vitest + Playwright, requiresnpm run test:browser:installfirst) - Test (e2e):
npm run test:e2e(Playwright) - Lint:
npm run lint(Biome 2.4) - Format:
npm run format(Biome, tabs, double quotes, 100-col) - i18n check:
npm run i18n:check(validates the 13 locale files)
src/— React app: UI, editor components, timeline, i18n, captioning/cursor/exporter libselectron/— main process, IPC, recording orchestrationelectron/native/— native capture helpers:screencapturekit/(Swift, macOS) andwgc-capture/(C++/Win32, Windows). These are built and shipped with the app, not loaded from npmdocs/— architecture, engineering roadmaps, testing guidestests/— Playwright e2e specs + fixturesscripts/— native build scripts, diagnostic toolsnix/,flake.nix— Linux packagingrelease/,dist-electron/— build artifacts (gitignored)
- TypeScript strict mode (
tsconfig.json). Noany(BiomenoExplicitAnyiswarn— don't add newany). - Biome handles lint AND format. Tabs, double quotes, 100-col width, LF line endings. Run
npm run lint:fixbefore committing. - React functional components only. Hooks at top level (Biome
useHookAtTopLeveliserror). - Imports: use the
useImportTypediscipline (Biome organizes them). - Husky + lint-staged runs Biome on staged
*.{ts,tsx,js,jsx,mts,cts,json}. - The repo is pre-1.x and not production-grade — rough edges are expected, but new code should be clean.
- Unit tests live next to source as
*.test.ts/*.test.tsx(Vitest, jsdom). - Browser tests use
vitest.browser.config.ts(Playwright headless) — only run when DOM/Pixi rendering matters. - E2E tests are in
tests/e2e/(Playwright). Some specs are platform-specific (e.g.windows-native-checklist.spec.ts). - Add a test for every new behavior in the same package as the code under test.
- All tests must pass before opening a PR. CI runs
npm run testandnpm run test:browseron every PR.
- Branch from
main; never push to it directly. - Commit messages: short imperative summary, optional body. Recent style mixes conventional-ish prefixes (
ci:,chore:,fix:) with plain messages — either is fine, just be consistent within a PR. - PR titles must follow Conventional Commits (
feat:,fix:,chore:,refactor:,perf:,docs:,test:,build:,ci:,style:,revert:). Enforced by thesemantic-prjob inci.yml. This feeds GitHub's auto-generated release notes with clean categories. - Open PR via
gh pr createonce CI is green. - PR template is in
.github/pull_request_template.md.
Two workflow_dispatch workflows cut a release with a pre-release candidate (RC) first, then promote to stable. Trunk-based, no extra branch. Full operational guide in .harness/docs/git-workflow.md § Release flow.
- Cut RC: Actions → "Cut a release candidate" → Run workflow. Inputs:
bump(patch|minor|major),rc_number(default 1), optionaltarget_versionoverride. Snaps issues out of the rollingNext Releasemilestone into a versionedvX.Y.Zmilestone, bumpspackage.json, pushes thevX.Y.Z-rc.Ntag, which triggers the existingbuild.ymlto publish a GitHub pre-release. Notarization is skipped on RCs. Notifies#rc-testingon Discord. - Promote RC: Actions → "Promote RC to stable release" → Run workflow. Input:
rc_tag(e.g.v1.5.0-rc.2), optionalrelease_notes_extra. Closes thevX.Y.Zmilestone, strips-rc.Nfrompackage.json, pushesvX.Y.Ztag, which triggersbuild.ymlto publish a stable release (full notarization, Tier 3 homebrew/winget/nix/aur fires). Notifies#announcementson Discord. - Manual fallback:
git tag vX.Y.Z-rc.N <sha> && git push origin vX.Y.Z-rc.Ndoes the same as Cut RC (minus the milestone migration and Discord announce) — useful for emergency cuts.
Both workflows require the OPENSCREEN_RELEASE_TOKEN secret (a fine-grained PAT with contents: write + issues: write). This is the standard fix for release: published not triggering downstream workflows when the release is created by GITHUB_TOKEN. See docs/secrets.md.
Release branches freeze the build between cut and promote. Every RC cut creates release/vX.Y.Z-rc.N. The branch is not merged into main until the stable tag is published; only cherry-picks of bugfixes land on the release branch during the RC window. The stable tag points at the branch tip (RC + cherry-picks), then promote.yml opens a release/vX.Y.Z-sync → main PR to bring main into line. This contract exists because of the v1.6.0 incident (2026-07-05) where the original promote workflow tagged main instead of the RC snapshot, causing 23 unreleased commits to ship in v1.6.0. Full rules in .harness/docs/git-workflow.md § Release branches.
- Never commit secrets.
.env.exampleexists; real.envis gitignored. macos.entitlementscontrols macOS permissions — review when touching native recorder.- Native helpers run with elevated privileges on user systems; treat code in
electron/*-helper/as security-sensitive.
- Native capture is platform-fragile: macOS uses ScreenCaptureKit (Swift), Windows uses WGC (C++/Win32). CI runs on Linux only — manual smoke test on real macOS/Windows is required for native changes.
- Pixi.js v8 is the rendering engine. Filters come from
pixi-filtersand@pixi/filter-drop-shadow. GSAP +motionfor animation. - i18n: 13 locales in
src/i18n/locales/<locale>/(e.g.src/i18n/locales/en/settings.json). Thei18n:checkscript validates them — run it after touching translation files. - Build pipeline:
npm run buildis full electron-builder. For iterating on renderer only, usenpm run build-vite(Vite + tsc, no packaging). - README tone: the project is explicitly "not production-grade" and free forever — don't add paywalls, premium tiers, or upsell language to UI/copy.