Repository navigation
Development
How to build RemuxForge from source. To use it, start at Home.
| For | You need |
|---|---|
| Any build | The .NET 10 SDK |
| Any build |
glslc and spirv-val on PATH, from the Vulkan SDK or the glslc / spirv-tools packages. Every build compiles and validates the compute shaders of RemuxForge.Vulkan. RemuxForge.Core references that project, so the CLI, the WebUI and the desktop app all need these two tools. |
| Desktop packages | Node.js/npm, Rust, and the platform prerequisites listed by Tauri 2: the Xcode command-line tools on macOS, the MSVC toolchain and WebView2 tooling on Windows |
| Running | The external tools RemuxForge drives at runtime: MKVToolNix (mkvmerge, mkvextract, mkvpropedit), ffmpeg/ffprobe and the MediaInfo CLI
|
On Windows x64 and Linux, RemuxForge can download a managed ffmpeg 9.0 build into its .remux-forge/ configuration folder when processing starts. On macOS it uses an installed ffmpeg (brew install ffmpeg-full).
RemuxForge.sln contains the first five projects below. The desktop host is in the same repository but outside the solution.
| Project | Contains |
|---|---|
RemuxForge.Core |
The engine: analysis, synchronization, audio, subtitles, splitting, metadata, chapters, AI preset generation, configuration and localization. Every front end depends on it. |
RemuxForge.Cli |
The command-line entry point, published as a self-contained single-file executable |
RemuxForge.Web |
The WebUI, built with Blazor Interactive Server and Radzen |
RemuxForge.Vulkan |
The Vulkan compute backend, built on Vortice.Vulkan: dHash, SIFT, matching and RANSAC pipelines, plus the GLSL shaders in Shaders/
|
RemuxForge.Vulkan.ShaderManifestTool |
A build-time tool that writes the shader manifest embedded in RemuxForge.Vulkan
|
RemuxForge.Desktop |
The Tauri 2 host, the sidecar preparation and the native packaging scripts |
Main folders in RemuxForge.Core:
| Folder | Responsibility |
|---|---|
Analysis/FrameSync/ |
FrameSync: measures one constant offset, and writes its diagnostics |
Analysis/Deep/, Analysis/Edit/
|
Deep Analysis: signal extraction, geometry, global offset solver, boundary and duration refinement, coverage verification, EditMap composition |
Analysis/Features/ |
SIFT matchers, on OpenCV (CPU) and on Vulkan |
Analysis/Speed/ |
Speed correction |
Ai/ |
AI preset generation for Metadata mode: context builder, tools, OpenAI Responses client, credentials and OAuth |
Audio/ |
The audio processing planner and renderer |
Chapters/ |
Chapter reading, timeline transforms and XML writing, shared by Split and Remux |
Configuration/ |
The settings service (remux presets included), validation, codec and language mapping |
Localization/ |
AppText and the Resources/en.json / it.json string tables |
Media/ |
Wrappers for ffmpeg, MediaInfo and MKVToolNix, frame access, geometry and timing |
Metadata/ |
Field and tag registries, expression engine, pipeline evaluator, execution service, preset service |
Models/ |
Data models; Models/Config/Options.cs holds the complete CLI parser |
Pipeline/ |
The remux pipeline: scanning, analysis coordination, track selection and mapping, merge preview, output |
Rename/ |
The bulk rename engine |
Splitting/ |
Split planning and execution, the analysis cache, cut-editor documents and edit commands, join, subtitle cutting |
Subtitles/ |
Subtitle canvas rewriting and subtitle timeline rewriting |
Tools/ |
External tool discovery and the managed ffmpeg download |
Transcoding/ |
Video encoding profiles |
In RemuxForge.Web, Components/Pages/Dashboard.razor and its code-behind coordinate the application. It is the only routable page, and it hosts:
- the shell, in
Components/Layout/; - the three workspaces, in
Components/Remux,Components/SplitandComponents/Metadata; - the EditMap editor and the Split cut editor.
Per-mode orchestrators and configuration drafts are in Services/, and shared dialogs and panels are in Components/Shared/. Radzen comes from NuGet and ASP.NET Core serves its static assets. Application styles are in wwwroot/css/ and the timeline scripts in wwwroot/js/.
# CLI
dotnet build RemuxForge.Cli -c Release
# WebUI
dotnet build RemuxForge.Web -c Release
# Docker image
docker build -t remuxforge .To build the shaders with debug information, add -p:VulkanShaderDebug=true. This switches glslc from -O to -O0 -g.
The CompileVulkanShaders target in RemuxForge.Vulkan.csproj runs before resources are prepared:
- For every
Shaders/*.comp, it runsglslc --target-env=vulkan1.2, thenspirv-valon the result. - It builds and runs
RemuxForge.Vulkan.ShaderManifestTool. The tool records the tool versions, the compile options and the ABI fromShaders/ShaderAbi.txt. For each shader it also records the bindings, push-constant size, local workgroup size and SHA-256. - The
.spvfiles and the manifest are embedded in the assembly.
At runtime, the shader loader checks each SPIR-V module against its manifest hash before it creates a pipeline.
The Dockerfile builds in mcr.microsoft.com/dotnet/sdk:10.0-resolute, with glslc and spirv-tools installed. It runs on mcr.microsoft.com/dotnet/aspnet:10.0. The runtime image:
- installs
mkvtoolnix,mediainfo,libvulkan1andmesa-vulkan-drivers; - adds the BtbN ffmpeg/ffprobe build from the 9.0 branch;
- sets
REMUXFORGE_PORT=5000andREMUXFORGE_DATA_DIR=/data; - exposes port 5000.
Pass --build-arg VERSION=x.y.z to stamp the version. docker-compose.yml runs the published draknodd/remuxforge:latest image, with /srv mounted on /data and /media mounted on /media.
CLI. The project already sets PublishSingleFile, SelfContained, EnableCompressionInSingleFile and PublishTrimmed=false. It declares the RIDs win-x64, linux-x64, linux-arm64, osx-x64 and osx-arm64:
dotnet publish RemuxForge.Cli -c Release -r win-x64
dotnet publish RemuxForge.Cli -c Release -r linux-x64
dotnet publish RemuxForge.Cli -c Release -r linux-arm64
dotnet publish RemuxForge.Cli -c Release -r osx-x64
dotnet publish RemuxForge.Cli -c Release -r osx-arm64WebUI. The Web project has no publish settings of its own, so pass them on the command line:
dotnet publish RemuxForge.Web -c Release -r linux-x64 --self-contained true \
-p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=trueRepeat with the other RIDs as needed. .NET publishing for a RID works across platforms, so one machine can produce every CLI and WebUI build.
The README also describes a release.sh script. It runs on a Linux release host and hands the native desktop builds to macOS and Windows workers. The script is kept outside the repository; .env.example lists the worker settings it reads.
RemuxForge.Desktop/package.json defines these scripts:
| Script | Does |
|---|---|
npm run prepare-sidecar |
Publishes the WebUI sidecar for the host platform, or for a RID passed after --
|
npm run dev |
Prepares the sidecar, then runs tauri dev
|
npm run build |
Prepares the sidecar, then runs tauri build for the host |
npm run build:macos-arm64 |
Prepares the osx-arm64 sidecar, then runs tauri build --target aarch64-apple-darwin --bundles dmg
|
npm run build:windows-x64 |
Prepares the win-x64 sidecar, then runs tauri build --target x86_64-pc-windows-msvc --bundles msi
|
cd RemuxForge.Desktop
npm install
npm run buildscripts/prepare-sidecar.mjs supports osx-arm64, osx-x64 and win-x64, and maps each RID to its Rust target triple. It:
- cleans
src-tauri/target/sidecar/<rid>andsrc-tauri/resources/wwwroot; - runs
dotnet publish RemuxForge.Web/RemuxForge.Web.csproj -c Release -r <rid> --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:DebugType=None, adding-p:Version=<version>when you pass a version as the second argument; - copies the executable to
src-tauri/binaries/remuxforge-web-<target-triple>[.exe], which Tauri bundles as theexternalBinsidecar; - copies the published
wwwrootintosrc-tauri/resources/wwwroot, which is bundled as an application resource; - converts the repository
LICENSEintosrc-tauri/LICENSE.rtfwithscripts/generate-license-rtf.mjs; the installer shows that file as its license.
A build with an explicit Rust target writes its bundles under src-tauri/target/<target>/release/bundle. A host build writes them under src-tauri/target/release/bundle. On Windows the configuration bundles an MSI. On macOS it bundles RemuxForge.app, and the dmg bundle wraps it.
The bundles are unsigned, so on first launch Windows SmartScreen and macOS Gatekeeper ask the user to confirm. Public distribution adds Authenticode signing on Windows, and Developer ID signing with notarization on macOS.
- The Tauri host starts the sidecar with
--desktop --port 0. The WebUI then binds to127.0.0.1, on a port chosen by the operating system. - Data goes to the native per-user local application-data directory, which is passed to the sidecar as
REMUXFORGE_DATA_DIR. - A local loader page shows "Starting RemuxForge…" until the sidecar prints its
REMUXFORGE_READY {"url": ...}line. Once the URL is confirmed to behttp://127.0.0.1, the window navigates to it. - If the sidecar stops unexpectedly, the loader shows the exit code and a Retry button that restarts it.
- A second launch focuses the existing window, so only one instance runs.
- On exit, the host writes
SHUTDOWNto the sidecar's standard input, which stops any running Remux, Split and Metadata work cooperatively. After 750 ms it terminates the process.
Every user-visible string is in RemuxForge.Core/Localization/Resources/en.json or it.json, both embedded in the Core assembly. Each file is a flat JSON object keyed by dotted names, such as web.remux.label.speed, metadata.field.audio_title or split.plan.reencodeSegment. A value is either a string or, for longer help texts, an array of lines that is joined with line breaks.
Code reads strings through AppText:
-
AppText.T("key")returns the string in the active language. -
AppText.F("key", args...)formats that string withstring.Formatand the invariant culture, for values with{0}placeholders. - A key missing from the active file is shown as
[key], so it stands out in the UI.
The language is chosen in this order: the CLI --lang option, the REMUXFORGE_LANG environment variable, the language saved in the settings, and English as the default. In the WebUI the Language menu switches it live.
The two files have the same keys. When you add UI text, add the key to both en.json and it.json. The in-app help panes read the web.*.help.* keys, so those keys are the reference description of each field.
- Open an issue for a bug or a behavior change before you send a large pull request.
- Include reproducible commands, your platform, the versions of the external tools, and the relevant MediaInfo or ffmpeg output.
- Keep each pull request to one change.
- Use your own media, or freely licensed media, for samples.
- Add every new user-facing string to both
en.jsonandit.json.
LLM-based assistance was used during development for the README and wiki documentation, for refining the WebUI design, and for broad refactoring support where useful.