Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -499,13 +499,15 @@ jobs:
uses: ./.github/actions/setup

# bsdtar (libarchive-tools) is fpm's mtree generator for the pacman target.
# rpmbuild (rpm) is what fpm shells out to for the rpm target; without it the
# build fails at packaging, not at config parse.
# patchelf is what build-linux-compositor-addon.mjs renames the ffmpeg symbols
# with, so the addon cannot bind to Chromium's bundled ffmpeg — an unconditional
# dependency that resolvePatchelf() throws on. It happens to be preinstalled on
# the ubuntu-24.04 image, which is why this has worked; declaring it means the
# build stops depending on the runner image's contents.
- name: Install Linux packaging and native build dependencies
run: sudo apt-get update && sudo apt-get install -y libarchive-tools patchelf
run: sudo apt-get update && sudo apt-get install -y libarchive-tools rpm patchelf

- name: Stage whisper-stt binaries
shell: bash
Expand All@@ -516,6 +518,30 @@ jobs:
- name: Build Linux app
run: npm run build:linux -- --publish never

# The guard for the trap documented on the upload step below: `if-no-files-found`
# evaluates the union of the globs, so a format that stops being produced is
# invisible there. It is a real failure mode and not a hypothetical one — the rpm
# target was added to electron-builder.json5's `linux.target` alone, where the CLI
# list in `build:linux` overrides it, and the upload glob for it would have matched
# nothing on every release with the job still green. One assertion per format.
- name: Verify every Linux format was produced
run: |
if [[ ! -d release ]]; then
echo "::error::electron-builder produced no release/ directory"
exit 1
fi
MISSING=()
for ext in AppImage deb pacman rpm; do
COUNT="$(find release -type f -name "*.${ext}" -printf . | wc -c)"
echo "${ext}: ${COUNT}"
if [[ "$COUNT" -eq 0 ]]; then MISSING+=("$ext"); fi
done
if [[ "${#MISSING[@]}" -gt 0 ]]; then
echo "::error::No artifact produced for: ${MISSING[*]} — check the target list in package.json's build:linux, which overrides linux.target in electron-builder.json5"
find release -maxdepth 2 -type f -print
exit 1
fi

- name: Upload Linux packages
uses: actions/upload-artifact@v4
with:
Expand All@@ -524,6 +550,7 @@ jobs:
release/**/*.AppImage
release/**/*.deb
release/**/*.pacman
release/**/*.rpm
# No *.zsync: nothing produces one. zsync is electron-updater's delta format,
# this repo has no updater (no electron-updater, no autoUpdater, no
# latest-linux.yml), and app-builder-lib 26.x dropped zsync entirely in favour
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,16 +83,21 @@ Download the `.exe` installer directly from the [Releases page](https://github.c

### Linux

Three packages are published to the [Releases page](https://github.com/getopenscreen/openscreen/releases) for each version. Pick the one that matches your distro:
Four packages are published to the [Releases page](https://github.com/getopenscreen/openscreen/releases) for each version. Pick the one that matches your distro:

**Debian / Ubuntu / Pop!_OS (`.deb`)**
```bash
sudo apt install ./Openscreen-Linux-latest.deb
sudo apt install ./Openscreen-Linux-*.deb
```

**Fedora / RHEL / CentOS (`.rpm`)**
```bash
sudo dnf install ./Openscreen-Linux-*.rpm
```

**Arch / Manjaro (`.pacman`)**
```bash
sudo pacman -U Openscreen-Linux-latest.pacman
sudo pacman -U Openscreen-Linux-*.pacman
```

**Any distro (`.AppImage`)**
Expand Down
34 changes: 33 additions & 1 deletion electron-builder.json5
Original file line numberDiff line numberDiff line change
Expand Up@@ -102,10 +102,16 @@
}
},
"linux": {
// Cette liste ne suffit PAS à produire un artefact en CI : `build:linux` passe
// ses cibles en ligne de commande (`electron-builder --linux AppImage deb pacman
// rpm`), et la CLI REMPLACE `linux.target` au lieu de le compléter. Toute cible
// ajoutée ici doit l'être aussi dans le script, sinon elle n'existe que pour un
// `electron-builder --linux` nu, que rien n'exécute.
"target": [
"AppImage",
"deb",
"pacman"
"pacman",
"rpm"
],
"icon": "icons/icons/png",
"artifactName": "${productName}-Linux-${version}.${ext}",
Expand DownExpand Up@@ -176,6 +182,32 @@
"vulkan-swrast"
]
},
"rpm": {
// Même règle que ci-dessus : la liste REMPLACE le défaut d'electron-builder,
// donc les huit premières entrées SONT ce défaut (FpmTarget.getDefaultDepends,
// cas "rpm"), verbatim, suivies des deux qui nous sont propres.
//
// `mesa-vulkan-drivers` porte le même nom sur Fedora que sur Debian : c'est le
// paquet qui garantit lavapipe, sans quoi l'aperçu du compositeur est indisponible.
//
// `libsecret` n'est PAS dans le défaut rpm alors qu'il l'est dans le défaut deb
// (`libsecret-1-0`). `safeStorage` chiffre les clés d'API des fournisseurs LLM
// (electron/ai-edition/llm-config-store.ts) et passe par le Secret Service :
// sans lui, `isEncryptionAvailable()` répond faux et l'enregistrement d'une clé
// lève. Une omission d'electron-builder, pas un choix.
"depends": [
"gtk3",
"libnotify",
"nss",
"libXScrnSaver",
"(libXtst or libXtst6)",
"xdg-utils",
"at-spi2-core",
"(libuuid or libuuid1)",
"libsecret",
"mesa-vulkan-drivers"
]
},
"win": {
"target": [
"nsis"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@
"build:native:linux": "node scripts/build-linux-pipewire-helper.mjs",
"build:win": "npm run build:native:win && npm run fetch:ffmpeg && npm run build:native:compositor && tsc && vite build && electron-builder --win --config.npmRebuild=false",
"build:win:store": "npm run build:native:win && npm run fetch:ffmpeg && npm run build:native:compositor && tsc && vite build && electron-builder --win appx --config.npmRebuild=false",
"build:linux": "npm run fetch:ffmpeg:sdk && npm run build:native:linux && npm run build:native:compositor:linux && tsc && vite build && electron-builder --linux AppImage deb pacman --config.npmRebuild=false",
"build:linux": "npm run fetch:ffmpeg:sdk && npm run build:native:linux && npm run build:native:compositor:linux && tsc && vite build && electron-builder --linux AppImage deb pacman rpm --config.npmRebuild=false",
"build:whisper-binaries": "bash scripts/build-whisper-stt.sh",
"test:whisper-stt": "node scripts/test-whisper-stt.mjs",
"test": "vitest --run",
Expand Down
4 changes: 2 additions & 2 deletions technical-documentation/engineering/build-and-packaging.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@ OpenScreen builds its renderer, Electron main process, preload bridge, native he
| `npm run build:mac` | Builds the ScreenCaptureKit and cursor helpers, checks TypeScript, runs Vite, and packages the macOS target. |
| `npm run build:win` | Builds WGC/cursor helpers and the D3D11 compositor addon, fetches FFmpeg, checks TypeScript, runs Vite, and packages the Windows NSIS target without npm rebuild. |
| `npm run build:win:store` | Performs the Windows native and renderer build, then asks electron-builder for the configured AppX Store package. |
| `npm run build:linux` | Checks TypeScript, runs Vite, then packages AppImage, Debian, and pacman artifacts without npm rebuild. |
| `npm run build:linux` | Checks TypeScript, runs Vite, then packages AppImage, Debian, pacman, and RPM artifacts without npm rebuild. Its explicit `--linux` target list overrides `linux.target` in `electron-builder.json5`, so a target added to the config alone is never built. |
| `npm run build:native:mac` | Uses SwiftPM to build requested single-architecture ScreenCaptureKit and macOS cursor helpers and stages them under `electron/native/bin/darwin-*`. |
| `npm run build:native:win` | Uses CMake/Ninja in an MSVC environment to build WGC capture and cursor-sampler executables and stage x64 binaries. |
| `npm run build:native:compositor` | Uses Cargo/MSVC and the pinned shared FFmpeg SDK to build `compositor_view.node`. |
Expand DownExpand Up@@ -124,7 +124,7 @@ Electron-builder targets DMG for both `arm64` and `x64`, enables hardened runtim

### Linux and Nix

Electron-builder produces AppImage, `.deb`, and `.pacman` targets. The flake separately supports `x86_64-linux` and `aarch64-linux`, offers NixOS and Home Manager modules, and builds a wrapper around nixpkgs' system Electron. `nix/package.nix` runs Vite directly, installs `dist/`, `dist-electron/`, production npm dependencies, wallpapers, icons, and a desktop entry; it does not invoke electron-builder. The release workflow later opens a PR to update the Nix package version and npm dependency hash after stable releases.
Electron-builder produces AppImage, `.deb`, `.pacman`, and `.rpm` targets. Each fpm target carries its own `depends` list, which *replaces* electron-builder's default rather than extending it; all three package formats therefore repeat that default verbatim before adding the Vulkan ICD (`mesa-vulkan-drivers`, `vulkan-swrast` on Arch) the native compositor needs. The RPM list also restores `libsecret`, which electron-builder includes in its `deb` default but omits from its `rpm` one, and which `safeStorage` needs to encrypt LLM credentials. The flake separately supports `x86_64-linux` and `aarch64-linux`, offers NixOS and Home Manager modules, and builds a wrapper around nixpkgs' system Electron. `nix/package.nix` runs Vite directly, installs `dist/`, `dist-electron/`, production npm dependencies, wallpapers, icons, and a desktop entry; it does not invoke electron-builder. The release workflow later opens a PR to update the Nix package version and npm dependency hash after stable releases.

## Node and toolchain versions

Expand Down
4 changes: 2 additions & 2 deletions technical-documentation/engineering/ci-workflows.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ flowchart TD
ReleaseBuild["build.yml<br/>v* tag or dispatch"] --> Win[Windows NSIS]
ReleaseBuild --> Store[Windows AppX]
ReleaseBuild --> Mac["macOS arm64 and x64 DMGs"]
ReleaseBuild --> Linux["AppImage, deb, pacman"]
ReleaseBuild --> Linux["AppImage, deb, pacman, rpm"]
Win --> Publish[GitHub release]
Mac --> Publish
Linux --> Publish
Expand DownExpand Up@@ -101,7 +101,7 @@ A `v*` tag or manual dispatch starts platform builds. Dispatch accepts `arch` (`
- `build-windows` runs `npm run build:win` and uploads `openscreen-windows` for 30 days.
- `build-windows-store` runs `npm run build:win:store` and uploads `openscreen-windows-store` for 30 days.
- `build-macos` is an `arm64`/`x64` matrix. It builds Vite/Electron and native helpers, packages and optionally signs the app, creates DMGs, notarizes every signed build including pre-releases, and uploads one artifact per architecture for 30 days.
- `build-linux` produces AppImage, deb, and pacman files and uploads `openscreen-linux` for 30 days. No zsync: that is electron-updater's delta format, this repo ships no updater, and app-builder-lib 26.x embeds a block map in the AppImage instead.
- `build-linux` produces AppImage, deb, pacman, and rpm files and uploads `openscreen-linux` for 30 days. It asserts one artifact per format before uploading, because `if-no-files-found: error` evaluates the union of the upload globs and so cannot catch a single format that stopped being produced. No zsync: that is electron-updater's delta format, this repo ships no updater, and app-builder-lib 26.x embeds a block map in the AppImage instead.
- `publish-release` waits for Windows NSIS, macOS, and Linux jobs; the Store job is not a dependency. It checks the tag against `package.json`, downloads the NSIS/macOS/Linux artifacts, and creates or updates a GitHub release with `OPENSCREEN_RELEASE_TOKEN`.

The build comments and package behavior refer to the local Whisper architecture documented in [transcription and captions](../architecture/transcription-and-captions.md). The STT model downloads to user data at runtime and is not a release-build asset.
Expand Down
10 changes: 8 additions & 2 deletions website/docs/installation.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,13 +2,14 @@
id: installation
title: Installation
sidebar_position: 2
description: "Install OpenScreen on macOS, Windows, or Linux — .dmg, .exe, .deb, .pacman, AppImage, and a Nix flake, including the macOS Gatekeeper step."
description: "Install OpenScreen on macOS, Windows, or Linux — .dmg, .exe, .deb, .rpm, .pacman, AppImage, and a Nix flake, including the macOS Gatekeeper step."
keywords:
- install screen recorder
- download OpenScreen
- macOS dmg
- Windows installer
- Linux deb
- Fedora rpm
- AppImage
- Nix flake
---
Expand DownExpand Up@@ -41,13 +42,18 @@ Download and run the `.exe` installer from [Releases](https://github.com/getopen

## Linux

Three packages are published per release — pick the one matching your distro.
Four packages are published per release — pick the one matching your distro.

**Debian / Ubuntu / Pop!_OS**
```bash
sudo apt install ./Openscreen-Linux-*.deb
```

**Fedora / RHEL / CentOS**
```bash
sudo dnf install ./Openscreen-Linux-*.rpm
```

**Arch / Manjaro**
```bash
sudo pacman -U Openscreen-Linux-*.pacman
Expand Down
1 change: 1 addition & 0 deletions website/src/lib/release.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,7 @@ export const ASSET_PATTERNS = {
macIntel: /Mac.*x64.*\.dmg$/i,
windows: /\.exe$/i,
deb: /\.deb$/i,
rpm: /\.rpm$/i,
pacman: /\.pacman$/i,
appImage: /\.AppImage$/i,
} as const;
Expand Down
3 changes: 2 additions & 1 deletion website/src/pages/download.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,7 +25,7 @@ const PAGE_URL = "https://getopenscreen.com/download/";
// structured-data description that contradicts the meta one is worse than none.
const PAGE_TITLE = "Download for Windows, macOS & Linux";
const PAGE_DESCRIPTION =
"Download OpenScreen free for Windows, macOS, and Linux — .dmg, .exe, .deb, .pacman, AppImage, and a Nix flake. Open source, no account, no watermark.";
"Download OpenScreen free for Windows, macOS, and Linux — .dmg, .exe, .deb, .rpm, .pacman, AppImage, and a Nix flake. Open source, no account, no watermark.";

type PlatformSpec = {
id: string;
Expand DownExpand Up@@ -60,6 +60,7 @@ const PLATFORMS: PlatformSpec[] = [
icon: TerminalSquare,
options: [
{ kind: "deb", label: "Debian, Ubuntu, Pop!_OS", sublabel: "Package · .deb" },
{ kind: "rpm", label: "Fedora, RHEL, CentOS", sublabel: "Package · .rpm" },
{ kind: "pacman", label: "Arch, Manjaro", sublabel: "Package · .pacman" },
{ kind: "appImage", label: "Any distribution", sublabel: "Portable · .AppImage" },
],
Expand Down
5 changes: 3 additions & 2 deletions website/src/pages/index.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -331,8 +331,9 @@ export default function Home() {
</div>

<p className={styles.quickStartNote}>
The macOS line is only needed if Gatekeeper blocks the app. Linux also ships
<code>.pacman</code>, an AppImage, and a Nix flake — every artifact is on the{" "}
The macOS line is only needed if Gatekeeper blocks the app. Linux also ships{" "}
<code>.rpm</code>, <code>.pacman</code>, an AppImage, and a Nix flake — every artifact
is on the{" "}
<a href="https://github.com/getopenscreen/openscreen/releases">Releases page</a>, and{" "}
<Link to="/docs/installation">Installation</Link> has the full steps.
</p>
Expand Down
Loading