Skip to content

Development

simonefil edited this page Oct 9, 2026 · 5 revisions

Development

How to build RemuxForge from source. To use it, start at Home.

Requirements

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).

Project layout

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/Split and Components/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/.

Build

# 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.

How the shaders are built

The CompileVulkanShaders target in RemuxForge.Vulkan.csproj runs before resources are prepared:

  1. For every Shaders/*.comp, it runs glslc --target-env=vulkan1.2, then spirv-val on the result.
  2. It builds and runs RemuxForge.Vulkan.ShaderManifestTool. The tool records the tool versions, the compile options and the ABI from Shaders/ShaderAbi.txt. For each shader it also records the bindings, push-constant size, local workgroup size and SHA-256.
  3. The .spv files 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.

Docker image

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, libvulkan1 and mesa-vulkan-drivers;
  • adds the BtbN ffmpeg/ffprobe build from the 9.0 branch;
  • sets REMUXFORGE_PORT=5000 and REMUXFORGE_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.

Publish

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-arm64

WebUI. 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=true

Repeat 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.

Desktop

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 build

Sidecar preparation

scripts/prepare-sidecar.mjs supports osx-arm64, osx-x64 and win-x64, and maps each RID to its Rust target triple. It:

  1. cleans src-tauri/target/sidecar/<rid> and src-tauri/resources/wwwroot;
  2. 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;
  3. copies the executable to src-tauri/binaries/remuxforge-web-<target-triple>[.exe], which Tauri bundles as the externalBin sidecar;
  4. copies the published wwwroot into src-tauri/resources/wwwroot, which is bundled as an application resource;
  5. converts the repository LICENSE into src-tauri/LICENSE.rtf with scripts/generate-license-rtf.mjs; the installer shows that file as its license.

Bundles

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.

Desktop runtime

  • The Tauri host starts the sidecar with --desktop --port 0. The WebUI then binds to 127.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 be http://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 SHUTDOWN to the sidecar's standard input, which stops any running Remux, Split and Metadata work cooperatively. After 750 ms it terminates the process.

Localization

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 with string.Format and 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.

Contributing

  • 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.json and it.json.

LLM usage notice

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.

Next

Clone this wiki locally