summaryrefslogtreecommitdiff
path: root/nix
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2026-07-30 20:12:09 +0200
committercashmere <cashmere@autistici.org>2026-07-30 20:12:09 +0200
commit465071d8232e74b1690280a38a86d435269fc35d (patch)
treef9ce8eb12cf87928eb9d528c1359e3fbb8e44b32 /nix
parent01509b53c6bc6e891c55da7093e1fdf5d29499d7 (diff)
downloadopencut-465071d8232e74b1690280a38a86d435269fc35d.tar.gz
build: replace flake with npins, add Nix packages for web and desktop
- npins pins nixpkgs-unstable + Inter font tarball; shell.nix replaces the flake devshell - nix/bun-deps.nix: fixed-output bun install of the workspace (hash tied to bun.lock) - nix/web.nix: static Next.js export; next/font/google patched to local Inter for offline builds - nix/desktop.nix: tsc-built Electron app embedding the web export, wrapped with nixpkgs electron; ffmpeg-static satisfied by nixpkgs ffmpeg
Diffstat (limited to 'nix')
-rw-r--r--nix/bun-deps.nix49
-rw-r--r--nix/desktop.nix86
-rw-r--r--nix/web.nix64
3 files changed, 199 insertions, 0 deletions
diff --git a/nix/bun-deps.nix b/nix/bun-deps.nix
new file mode 100644
index 00000000..646a91d7
--- /dev/null
+++ b/nix/bun-deps.nix
@@ -0,0 +1,49 @@
+# Fixed-output derivation: workspace node_modules from bun.lock.
+# Only re-runs when the lockfile or manifests change; the hash covers the
+# installed dependency tree, so it must be updated whenever bun.lock changes
+# (set outputHash = lib.fakeHash, build once, paste the reported hash).
+{
+ lib,
+ runCommand,
+ bun,
+ cacert,
+}:
+
+let
+ minimalSrc = runCommand "opencut-bun-src" { } ''
+ mkdir -p $out/apps/web $out/apps/desktop
+ cp ${../package.json} $out/package.json
+ cp ${../bun.lock} $out/bun.lock
+ cp ${../bunfig.toml} $out/bunfig.toml
+ cp ${../.npmrc} $out/.npmrc
+ cp ${../apps/web/package.json} $out/apps/web/package.json
+ cp ${../apps/desktop/package.json} $out/apps/desktop/package.json
+ '';
+in
+runCommand "opencut-bun-deps"
+ {
+ nativeBuildInputs = [
+ bun
+ cacert
+ ];
+ outputHashMode = "recursive";
+ outputHashAlgo = "sha256";
+ outputHash = "sha256-+zRGGTHFoM9d4wjP999J3JdcRgNksTTVOb+nceyvNak=";
+ }
+ ''
+ cp -r ${minimalSrc} src
+ chmod -R u+w src
+ cd src
+
+ export HOME=$TMPDIR
+ export BUN_INSTALL_CACHE_DIR=$TMPDIR/bun-cache
+ # The electron binary is unused; nixpkgs electron is used at runtime.
+ export ELECTRON_SKIP_BINARY_DOWNLOAD=1
+
+ bun install --frozen-lockfile
+
+ mkdir -p $out/apps/web $out/apps/desktop
+ cp -r node_modules $out/node_modules
+ cp -r apps/web/node_modules $out/apps/web/node_modules
+ cp -r apps/desktop/node_modules $out/apps/desktop/node_modules
+ ''
diff --git a/nix/desktop.nix b/nix/desktop.nix
new file mode 100644
index 00000000..de2c8660
--- /dev/null
+++ b/nix/desktop.nix
@@ -0,0 +1,86 @@
+# Electron desktop app: tsc-compiled main process + the static web export,
+# wrapped with nixpkgs electron (no electron-builder, no asar).
+# ffmpeg-static is satisfied by nixpkgs ffmpeg.
+{
+ lib,
+ stdenvNoCC,
+ bun,
+ nodejs,
+ callPackage,
+ electron,
+ ffmpeg,
+ makeWrapper,
+ sources ? import ../npins,
+}:
+
+let
+ bunDeps = callPackage ./bun-deps.nix { };
+ web = callPackage ./web.nix { inherit sources; };
+ desktopPkg = builtins.fromJSON (builtins.readFile ../apps/desktop/package.json);
+in
+stdenvNoCC.mkDerivation {
+ pname = "opencut-desktop";
+ version = desktopPkg.version;
+ src = lib.cleanSource ../.;
+
+ nativeBuildInputs = [
+ bun
+ nodejs
+ makeWrapper
+ ];
+
+ configurePhase = ''
+ runHook preConfigure
+ cp -r ${bunDeps}/node_modules node_modules
+ cp -r ${bunDeps}/apps/desktop/node_modules apps/desktop/node_modules
+ chmod -R u+w node_modules apps/desktop/node_modules
+ patchShebangs node_modules apps/desktop/node_modules
+ runHook postConfigure
+ '';
+
+ buildPhase = ''
+ runHook preBuild
+ export HOME=$TMPDIR
+ cd apps/desktop
+ bun run build
+ cd $NIX_BUILD_TOP/source
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ appdir=$out/share/opencut
+ mkdir -p $appdir/node_modules/ffmpeg-static
+ cp apps/desktop/package.json $appdir/package.json
+ cp -r apps/desktop/dist $appdir/dist
+ cp -r ${web} $appdir/web
+
+ # main.js resolves ffmpeg via require("ffmpeg-static"); point it at nixpkgs ffmpeg.
+ cp apps/desktop/node_modules/ffmpeg-static/index.js $appdir/node_modules/ffmpeg-static/index.js
+ cp apps/desktop/node_modules/ffmpeg-static/package.json $appdir/node_modules/ffmpeg-static/package.json
+ ln -s ${lib.getExe ffmpeg} $appdir/node_modules/ffmpeg-static/ffmpeg
+
+ makeWrapper ${lib.getExe electron} $out/bin/opencut \
+ --add-flags "$appdir"
+
+ mkdir -p $out/share/applications
+ cat > $out/share/applications/opencut.desktop <<EOF
+ [Desktop Entry]
+ Type=Application
+ Name=OpenCut
+ Comment=Offline-first video editor
+ Exec=opencut
+ Categories=AudioVideo;Video;
+ EOF
+
+ runHook postInstall
+ '';
+
+ meta = {
+ description = "OpenCut desktop (Electron)";
+ license = lib.licenses.mit;
+ mainProgram = "opencut";
+ platforms = lib.platforms.linux;
+ };
+}
diff --git a/nix/web.nix b/nix/web.nix
new file mode 100644
index 00000000..eb464a2a
--- /dev/null
+++ b/nix/web.nix
@@ -0,0 +1,64 @@
+# Static export of the Next.js web app (apps/web/out).
+# Deps come from the bun-deps FOD; the Google-font fetch in next/font is
+# replaced by the npins-pinned Inter so the build runs offline.
+{
+ lib,
+ stdenvNoCC,
+ bun,
+ nodejs,
+ callPackage,
+ sources ? import ../npins,
+}:
+
+let
+ bunDeps = callPackage ./bun-deps.nix { };
+ webPkg = builtins.fromJSON (builtins.readFile ../apps/web/package.json);
+in
+stdenvNoCC.mkDerivation {
+ pname = "opencut-web";
+ version = webPkg.version;
+ src = lib.cleanSource ../.;
+
+ nativeBuildInputs = [
+ bun
+ nodejs
+ ];
+
+ postPatch = ''
+ mkdir -p apps/web/public/fonts
+ cp ${sources.inter}/web/InterVariable.woff2 apps/web/public/fonts/InterVariable.woff2
+ substituteInPlace apps/web/src/app/layout.tsx \
+ --replace-fail 'import { Inter } from "next/font/google";' 'import localFont from "next/font/local";' \
+ --replace-fail 'const siteFont = Inter({ subsets: ["latin"] });' 'const siteFont = localFont({ src: "../../public/fonts/InterVariable.woff2" });'
+ '';
+
+ configurePhase = ''
+ runHook preConfigure
+ cp -r ${bunDeps}/node_modules node_modules
+ cp -r ${bunDeps}/apps/web/node_modules apps/web/node_modules
+ chmod -R u+w node_modules apps/web/node_modules
+ patchShebangs node_modules apps/web/node_modules
+ runHook postConfigure
+ '';
+
+ buildPhase = ''
+ runHook preBuild
+ export HOME=$TMPDIR
+ export NEXT_TELEMETRY_DISABLED=1
+ export NODE_ENV=production
+ cd apps/web
+ bun run build
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+ cp -r out $out
+ runHook postInstall
+ '';
+
+ meta = {
+ description = "OpenCut web app (static export)";
+ license = lib.licenses.mit;
+ };
+}