diff --git a/pkgs/by-name/le/legendsviewer-next/deps.json b/pkgs/by-name/le/legendsviewer-next/deps.json
new file mode 100644
index 000000000000..6e3e9e7b8218
--- /dev/null
+++ b/pkgs/by-name/le/legendsviewer-next/deps.json
@@ -0,0 +1,112 @@
+[
+ {
+ "pname": "Castle.Core",
+ "version": "5.1.1",
+ "hash": "sha256-oVkQB+ON7S6Q27OhXrTLaxTL0kWB58HZaFFuiw4iTrE="
+ },
+ {
+ "pname": "coverlet.collector",
+ "version": "6.0.0",
+ "hash": "sha256-IEmweTMapcPhFHpmJsPXfmMhravYOrWupgjeOvMmQ4o="
+ },
+ {
+ "pname": "Microsoft.CodeCoverage",
+ "version": "17.8.0",
+ "hash": "sha256-cv/wAXfTNS+RWEsHWNKqRDHC7LOQSSdFJ1a9cZuSfJw="
+ },
+ {
+ "pname": "Microsoft.Extensions.ApiDescription.Server",
+ "version": "6.0.5",
+ "hash": "sha256-RJjBWz+UHxkQE2s7CeGYdTZ218mCufrxl0eBykZdIt4="
+ },
+ {
+ "pname": "Microsoft.NET.Test.Sdk",
+ "version": "17.8.0",
+ "hash": "sha256-uz7QvW+NsVRsp8FR1wjnGEOkUaPX4JyieywvCN6g2+s="
+ },
+ {
+ "pname": "Microsoft.OpenApi",
+ "version": "1.6.14",
+ "hash": "sha256-dSJUic2orPGfYVgto9DieRckbtLpPyxHtf+RJ2tmKPM="
+ },
+ {
+ "pname": "Microsoft.TestPlatform.ObjectModel",
+ "version": "17.8.0",
+ "hash": "sha256-9TwGrjVvbtyetw67Udp3EMK5MX8j0RFRjduxPCs9ESw="
+ },
+ {
+ "pname": "Microsoft.TestPlatform.TestHost",
+ "version": "17.8.0",
+ "hash": "sha256-+CTYFu631uovLCO47RKe86YaAqfoLA4r73vKORJUsjg="
+ },
+ {
+ "pname": "Moq",
+ "version": "4.20.70",
+ "hash": "sha256-O+Ed1Hv8fK8MKaRh7qFGbsSPaTAj4O+yaLQ/W/ju7ks="
+ },
+ {
+ "pname": "MSTest.TestAdapter",
+ "version": "3.1.1",
+ "hash": "sha256-TLysbO9bgiztIap44o875ZPpuVAOC6ueaRTKsiVicXg="
+ },
+ {
+ "pname": "MSTest.TestFramework",
+ "version": "3.1.1",
+ "hash": "sha256-Vqu+IDuYjiR39QOJW7GHiH7CeF2cBfNIYYTXmVeeb9E="
+ },
+ {
+ "pname": "Newtonsoft.Json",
+ "version": "13.0.1",
+ "hash": "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo="
+ },
+ {
+ "pname": "NuGet.Frameworks",
+ "version": "6.5.0",
+ "hash": "sha256-ElqfN4CcKxT3hP2qvxxObb4mnBlYG89IMxO0Sm5oZ2g="
+ },
+ {
+ "pname": "SkiaSharp",
+ "version": "2.88.8",
+ "hash": "sha256-rD5gc4SnlRTXwz367uHm8XG5eAIQpZloGqLRGnvNu0A="
+ },
+ {
+ "pname": "SkiaSharp.NativeAssets.Linux",
+ "version": "2.88.8",
+ "hash": "sha256-fOmNbbjuTazIasOvPkd2NPmuQHVCWPnow7AxllRGl7Y="
+ },
+ {
+ "pname": "SkiaSharp.NativeAssets.macOS",
+ "version": "2.88.8",
+ "hash": "sha256-CdcrzQHwCcmOCPtS8EGtwsKsgdljnH41sFytW7N9PmI="
+ },
+ {
+ "pname": "SkiaSharp.NativeAssets.Win32",
+ "version": "2.88.8",
+ "hash": "sha256-b8Vb94rNjwPKSJDQgZ0Xv2dWV7gMVFl5GwTK/QiZPPM="
+ },
+ {
+ "pname": "Swashbuckle.AspNetCore",
+ "version": "6.9.0",
+ "hash": "sha256-fmJjAfVHzbw/31IFPFUP31g46Y1XXIc1kr6VvYW5pCc="
+ },
+ {
+ "pname": "Swashbuckle.AspNetCore.Swagger",
+ "version": "6.9.0",
+ "hash": "sha256-8KM21CWckFghGaqWahMa3V64+hUBrifAJnQ6P2VXlEk="
+ },
+ {
+ "pname": "Swashbuckle.AspNetCore.SwaggerGen",
+ "version": "6.9.0",
+ "hash": "sha256-Ni8Z9CFs+ybTX8IgDuSKA580ISQ55w032EeqWYQXwoc="
+ },
+ {
+ "pname": "Swashbuckle.AspNetCore.SwaggerUI",
+ "version": "6.9.0",
+ "hash": "sha256-V+3bEEpxSXPi9Sy1hHZEjY9qxuIpRWV5dKzaqYMSu40="
+ },
+ {
+ "pname": "System.Diagnostics.EventLog",
+ "version": "6.0.0",
+ "hash": "sha256-zUXIQtAFKbiUMKCrXzO4mOTD5EUphZzghBYKXprowSM="
+ }
+]
diff --git a/pkgs/by-name/le/legendsviewer-next/frontend.nix b/pkgs/by-name/le/legendsviewer-next/frontend.nix
new file mode 100644
index 000000000000..34aa35831fbd
--- /dev/null
+++ b/pkgs/by-name/le/legendsviewer-next/frontend.nix
@@ -0,0 +1,44 @@
+{
+ version,
+ src,
+ patches,
+
+ lib,
+ nodejs_22,
+
+ buildNpmPackage,
+}:
+buildNpmPackage {
+ pname = "legends-viewer-frontend";
+
+ inherit version src patches;
+
+ nodejs = nodejs_22;
+ npmDepsHash = "sha256-Hlo+G/d0glDutBwQU1Y5rfLD7IcfWtAClJPyrX5QBQg=";
+
+ postPatch = ''
+ cd "./LegendsViewer.Frontend/legends-viewer-frontend"
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ mkdir -p $out
+ cp -r ./dist $out
+
+ runHook postInstall
+ '';
+
+ meta = {
+ description = "Recreates Dwarf Fortress' Legends Mode from exported files";
+ homepage = "https://github.com/Kromtec/LegendsViewer-Next";
+ license = lib.licenses.mit;
+ platforms = [
+ "aarch64-darwin"
+ "x86_64-darwin"
+ "aarch64-linux"
+ "x86_64-linux"
+ ];
+ maintainers = with lib.maintainers; [ donottellmetonottellyou ];
+ };
+}
diff --git a/pkgs/by-name/le/legendsviewer-next/package.nix b/pkgs/by-name/le/legendsviewer-next/package.nix
new file mode 100644
index 000000000000..96e4eeff46a2
--- /dev/null
+++ b/pkgs/by-name/le/legendsviewer-next/package.nix
@@ -0,0 +1,155 @@
+{
+ patches ? [ ],
+
+ lib,
+ dotnetCorePackages,
+ curl,
+
+ buildDotnetModule,
+ callPackage,
+ copyDesktopItems,
+ fetchFromGitHub,
+ makeDesktopItem,
+ nix-update-script,
+}:
+let
+ version = "1.2.5";
+
+ src = fetchFromGitHub {
+ owner = "Kromtec";
+ repo = "LegendsViewer-Next";
+ tag = "v${version}";
+ hash = "sha256-R84y+QdLiEoVTo+z3jaql8m2rg2nbX9aXa2m8JiYAzU=";
+ };
+
+ patches' = patches ++ [ ./remove-npm-frontend.patch ];
+
+ frontend = callPackage ./frontend.nix {
+ inherit version src;
+ patches = patches';
+ };
+in
+buildDotnetModule rec {
+ pname = "legendsviewer-next";
+ inherit version src;
+ patches = patches';
+
+ strictDeps = true;
+ __structuredAttrs = true;
+
+ desktopItems = [
+ (makeDesktopItem {
+ name = pname;
+ desktopName = "Legends Viewer";
+ genericName = "DF Legends Export Browser";
+ comment = meta.description;
+ icon = "${frontend}/dist/ceretelina.png";
+ tryExec = meta.mainProgram;
+ exec = meta.mainProgram;
+
+ categories = [
+ "Game"
+ "RolePlaying"
+ "Simulation"
+ ];
+ keywords = [
+ "df"
+ "dwarf"
+ "fortress"
+ "legends"
+ "viewer"
+ ];
+ })
+ ];
+
+ dotnet-sdk = dotnetCorePackages.sdk_10_0;
+ dotnet-runtime = dotnetCorePackages.aspnetcore_10_0;
+
+ # File generated with `nix-build -A package.passthru.fetch-deps`
+ nugetDeps = ./deps.json;
+
+ projectFile = "./LegendsViewer.Backend/LegendsViewer.Backend.csproj";
+ testProjectFile = "./LegendsViewer.Backend.Tests/LegendsViewer.Backend.Tests.csproj";
+ executables = [ meta.mainProgram ];
+
+ nativeBuildInputs = [
+ copyDesktopItems
+ ];
+
+ installPhase = ''
+ runHook preInstall
+
+ lib=$out/lib/legendsviewer-next
+
+ mkdir -p $lib
+
+ cp ./LegendsViewer.Backend/bin/Release/*/*/* $lib
+ ln -s ${frontend} $lib/legends-viewer-frontend
+
+ runHook postInstall
+ '';
+
+ doInstallCheck = true;
+
+ nativeInstallCheckInputs = [
+ curl
+ ];
+
+ installCheckPhase = ''
+ runHook preInstallCheck
+
+ # Do not use coproc (on darwin)
+ $out/bin/LegendsViewer > /dev/null 2>&1 &
+ LEGENDSVIEWER_PID=$!
+
+ # Prevent hang on darwin
+ cleanup() {
+ kill -KILL "$LEGENDSVIEWER_PID"
+ }
+ trap cleanup EXIT
+
+ echo "Wait for server (max ~5 minutes):"
+ for i in $(seq 1 300); do
+ sleep 1
+ if curl -fsS http://localhost:15421/api/version > /dev/null; then
+ echo "Server is up!"
+ break
+ fi
+ echo "Retrying $i / 300"
+ done
+
+ echo "Version matches expected?"
+ if ! curl -fsS http://localhost:15421/api/version | grep -F "${version}"; then
+ echo "Version check failed"
+ exit 1
+ fi
+
+ echo "Static html server is up?"
+ if ! curl -fsS http://localhost:15422 | grep ""; then
+ echo "Static html check failed"
+ exit 1
+ fi
+
+ # Cleanup, no longer need trap
+ cleanup
+ trap - EXIT
+
+ runHook postInstallCheck
+ '';
+
+ passthru = {
+ updateScript = nix-update-script { };
+ };
+
+ meta = {
+ description = "Recreates Dwarf Fortress' Legends Mode from exported files";
+ homepage = "https://github.com/Kromtec/LegendsViewer-Next";
+ license = lib.licenses.mit;
+ mainProgram = "LegendsViewer";
+ platforms = [
+ "aarch64-linux"
+ "x86_64-linux"
+ ];
+ maintainers = with lib.maintainers; [ donottellmetonottellyou ];
+ };
+}
diff --git a/pkgs/by-name/le/legendsviewer-next/remove-npm-frontend.patch b/pkgs/by-name/le/legendsviewer-next/remove-npm-frontend.patch
new file mode 100644
index 000000000000..025675d52d8a
--- /dev/null
+++ b/pkgs/by-name/le/legendsviewer-next/remove-npm-frontend.patch
@@ -0,0 +1,21 @@
+diff --git a/LegendsViewer.Frontend/LegendsViewer.Frontend.csproj b/LegendsViewer.Frontend/LegendsViewer.Frontend.csproj
+index 3275f9c..aac315e 100644
+--- a/LegendsViewer.Frontend/LegendsViewer.Frontend.csproj
++++ b/LegendsViewer.Frontend/LegendsViewer.Frontend.csproj
+@@ -21,16 +21,8 @@
+
+
+
+-
+-
+-
+-
+
+
+-
+-
+-
+-
+
+
+