feat: add Nix flake with dev shell, package, and NixOS/Home Manager modules
Reproducible development environment for NixOS/Nix contributors: - Dev shell with Node 22, system Electron, Playwright, LD_LIBRARY_PATH for X11/Wayland/audio libs, activated automatically via direnv - buildNpmPackage derivation wrapping system Electron with desktop file and hicolor icons - NixOS module (programs.openscreen.enable) with xdg-desktop-portal - Home Manager module for per-user installation - Overlay for composing with other flakes Tested: nix flake show, nix develop, nix build, nixos-rebuild switch
This commit is contained in:
+6
-1
@@ -33,4 +33,9 @@ test-results
|
||||
playwright-report/
|
||||
|
||||
# Vitest browser mode screenshots
|
||||
__screenshots__/
|
||||
__screenshots__/
|
||||
|
||||
# Nix
|
||||
result
|
||||
result-*
|
||||
.direnv/
|
||||
Generated
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1775710090,
|
||||
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
description = "OpenScreen — desktop screen recorder with built-in editor";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs }:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
|
||||
in
|
||||
{
|
||||
# -- Per-system outputs (packages, dev shells) --
|
||||
|
||||
packages = forAllSystems (pkgs: {
|
||||
openscreen = pkgs.callPackage ./nix/package.nix { };
|
||||
default = self.packages.${pkgs.stdenv.hostPlatform.system}.openscreen;
|
||||
});
|
||||
|
||||
devShells = forAllSystems (
|
||||
pkgs:
|
||||
let
|
||||
electron = pkgs.electron;
|
||||
|
||||
# Libraries Electron needs at runtime on Linux
|
||||
runtimeLibs = with pkgs; [
|
||||
# X11
|
||||
libx11
|
||||
libxcomposite
|
||||
libxdamage
|
||||
libxext
|
||||
libxfixes
|
||||
libxrandr
|
||||
libxtst
|
||||
libxcb
|
||||
libxshmfence
|
||||
|
||||
# Wayland
|
||||
wayland
|
||||
|
||||
# GTK / UI toolkit
|
||||
gtk3
|
||||
glib
|
||||
pango
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
atk
|
||||
at-spi2-atk
|
||||
at-spi2-core
|
||||
|
||||
# Graphics
|
||||
mesa
|
||||
libGL
|
||||
libdrm
|
||||
vulkan-loader
|
||||
|
||||
# Networking / crypto (NSS for Chromium)
|
||||
nss
|
||||
nspr
|
||||
|
||||
# Audio
|
||||
alsa-lib
|
||||
pipewire
|
||||
pulseaudio
|
||||
|
||||
# System
|
||||
dbus
|
||||
cups
|
||||
expat
|
||||
libnotify
|
||||
libsecret
|
||||
util-linux # libuuid
|
||||
];
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
nodejs_22
|
||||
electron
|
||||
|
||||
# Native module compilation
|
||||
python3
|
||||
pkg-config
|
||||
gcc
|
||||
|
||||
# Playwright browser tests
|
||||
playwright-driver.browsers
|
||||
];
|
||||
|
||||
# Electron's prebuilt binary needs these at runtime
|
||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath runtimeLibs;
|
||||
|
||||
# Tell the npm `electron` package to use the Nix-provided binary
|
||||
# instead of downloading its own. vite-plugin-electron respects this.
|
||||
ELECTRON_OVERRIDE_DIST_PATH = "${electron}/lib/electron";
|
||||
|
||||
# Playwright browser path for test:browser / test:e2e
|
||||
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "1";
|
||||
|
||||
shellHook = ''
|
||||
echo "OpenScreen dev shell — node $(node --version), electron v$(electron --version 2>/dev/null | tr -d 'v')"
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
# -- System-wide outputs (modules, overlay) --
|
||||
|
||||
overlays.default = final: _prev: {
|
||||
openscreen = self.packages.${final.stdenv.hostPlatform.system}.openscreen;
|
||||
};
|
||||
|
||||
nixosModules.default = import ./nix/module.nix self;
|
||||
homeManagerModules.default = import ./nix/hm-module.nix self;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Home Manager module for OpenScreen
|
||||
# Usage in flake-based Home Manager config:
|
||||
#
|
||||
# inputs.openscreen.url = "github:siddharthvaddem/openscreen";
|
||||
#
|
||||
# { inputs, ... }: {
|
||||
# imports = [ inputs.openscreen.homeManagerModules.default ];
|
||||
# programs.openscreen.enable = true;
|
||||
# }
|
||||
self:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.programs.openscreen;
|
||||
in
|
||||
{
|
||||
options.programs.openscreen = {
|
||||
enable = lib.mkEnableOption "OpenScreen screen recorder";
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = self.packages.${pkgs.stdenv.hostPlatform.system}.openscreen;
|
||||
defaultText = lib.literalExpression "inputs.openscreen.packages.\${pkgs.stdenv.hostPlatform.system}.openscreen";
|
||||
description = "The OpenScreen package to use.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# NixOS module for OpenScreen
|
||||
# Usage in flake-based NixOS config:
|
||||
#
|
||||
# inputs.openscreen.url = "github:siddharthvaddem/openscreen";
|
||||
#
|
||||
# { inputs, ... }: {
|
||||
# imports = [ inputs.openscreen.nixosModules.default ];
|
||||
# programs.openscreen.enable = true;
|
||||
# }
|
||||
self:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.programs.openscreen;
|
||||
in
|
||||
{
|
||||
options.programs.openscreen = {
|
||||
enable = lib.mkEnableOption "OpenScreen screen recorder";
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = self.packages.${pkgs.stdenv.hostPlatform.system}.openscreen;
|
||||
defaultText = lib.literalExpression "inputs.openscreen.packages.\${pkgs.stdenv.hostPlatform.system}.openscreen";
|
||||
description = "The OpenScreen package to use.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
# Screen capture on Wayland requires xdg-desktop-portal.
|
||||
# We enable the base portal; users should also enable a
|
||||
# desktop-specific portal (e.g. xdg-desktop-portal-gtk,
|
||||
# xdg-desktop-portal-hyprland) in their DE config.
|
||||
xdg.portal.enable = lib.mkDefault true;
|
||||
};
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
{
|
||||
lib,
|
||||
buildNpmPackage,
|
||||
nodejs_22,
|
||||
electron,
|
||||
makeWrapper,
|
||||
makeDesktopItem,
|
||||
copyDesktopItems,
|
||||
}:
|
||||
|
||||
buildNpmPackage {
|
||||
nodejs = nodejs_22;
|
||||
pname = "openscreen";
|
||||
version = "1.3.0";
|
||||
|
||||
src =
|
||||
let
|
||||
fs = lib.fileset;
|
||||
maybe = fs.maybeMissing;
|
||||
in
|
||||
fs.toSource {
|
||||
root = ../.;
|
||||
fileset = fs.difference ../. (
|
||||
fs.unions [
|
||||
../nix
|
||||
../flake.nix
|
||||
../flake.lock
|
||||
(maybe ../release)
|
||||
(maybe ../test-results)
|
||||
(maybe ../playwright-report)
|
||||
(maybe ../.github)
|
||||
(maybe ../.vscode)
|
||||
(maybe ../.idea)
|
||||
(maybe ../.kiro)
|
||||
(maybe ../.envrc)
|
||||
(maybe ../.direnv)
|
||||
(fs.fileFilter (file: file.hasExt "md") ../.)
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
npmDepsHash = "sha256-Pd6J9TuggA9vM4s/LjdoK4MoBEivSzAWc/G2+pFOM2U=";
|
||||
|
||||
env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
|
||||
|
||||
# electron-builder is not needed — we wrap system electron directly
|
||||
npmFlags = [ "--ignore-scripts" ];
|
||||
makeCacheWritable = true;
|
||||
|
||||
# vite-plugin-electron compiles electron/ sources into dist-electron/
|
||||
# tsconfig has noEmit — tsc is type-check only
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
npx vite build
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p "$out/lib/openscreen"
|
||||
|
||||
# Renderer build output (index.html, JS chunks, copied public/ assets)
|
||||
cp -r dist "$out/lib/openscreen/"
|
||||
|
||||
# Main process + preload (compiled by vite-plugin-electron)
|
||||
cp -r dist-electron "$out/lib/openscreen/"
|
||||
|
||||
# Package manifest (electron reads "main" field to find entry point)
|
||||
cp package.json "$out/lib/openscreen/"
|
||||
|
||||
# Strip devDependencies (electron, vitest, biome, playwright, etc.)
|
||||
npm prune --omit=dev --no-save
|
||||
cp -r node_modules "$out/lib/openscreen/"
|
||||
|
||||
# Asset resolution: when app.isPackaged is false, the main process resolves
|
||||
# assets at <appPath>/public/assets/. Mirror the electron-builder
|
||||
# extraResources layout so wallpapers load correctly.
|
||||
mkdir -p "$out/lib/openscreen/public/assets"
|
||||
cp -r public/wallpapers "$out/lib/openscreen/public/assets/wallpapers"
|
||||
|
||||
# Wrap system electron with the app directory
|
||||
mkdir -p "$out/bin"
|
||||
makeWrapper "${electron}/bin/electron" "$out/bin/openscreen" \
|
||||
--add-flags "$out/lib/openscreen" \
|
||||
--set ELECTRON_IS_DEV 0
|
||||
|
||||
# Install icons to hicolor theme
|
||||
for size in 16 24 32 48 64 128 256 512 1024; do
|
||||
icon="icons/icons/png/''${size}x''${size}.png"
|
||||
if [ -f "$icon" ]; then
|
||||
install -Dm644 "$icon" \
|
||||
"$out/share/icons/hicolor/''${size}x''${size}/apps/openscreen.png"
|
||||
fi
|
||||
done
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
nativeBuildInputs = [
|
||||
makeWrapper
|
||||
copyDesktopItems
|
||||
];
|
||||
|
||||
desktopItems = [
|
||||
(makeDesktopItem {
|
||||
name = "openscreen";
|
||||
desktopName = "OpenScreen";
|
||||
genericName = "Screen Recorder";
|
||||
exec = "openscreen %U";
|
||||
icon = "openscreen";
|
||||
comment = "Desktop screen recorder with built-in editor";
|
||||
categories = [
|
||||
"AudioVideo"
|
||||
"Video"
|
||||
"Recorder"
|
||||
];
|
||||
startupWMClass = "Openscreen";
|
||||
terminal = false;
|
||||
})
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "Desktop screen recorder with built-in editor";
|
||||
homepage = "https://github.com/siddharthvaddem/openscreen";
|
||||
license = lib.licenses.mit;
|
||||
mainProgram = "openscreen";
|
||||
platforms = lib.platforms.linux;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user