Initial configuration, untested.

This commit is contained in:
Chris Toph 2025-06-29 19:34:36 -04:00
commit b9ec00c18c
17 changed files with 1510 additions and 0 deletions

23
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,23 @@
{
"recommendations": [
"bierner.emojisense",
"mkhl.direnv",
"irongeek.vscode-env",
"bmalehorn.vscode-fish",
"github.copilot",
"github.copilot-chat",
"golang.go",
"eamodio.gitlens",
"mblet.highlight-regex",
"oderwat.indent-rainbow",
"visualstudioexptteam.vscodeintellicode",
"visualstudioexptteam.intellicode-api-usage-examples",
"yzhang.markdown-all-in-one",
"shd101wyy.markdown-preview-enhanced",
"bierner.markdown-preview-github-styles",
"bbenoist.nix",
"brettm12345.nixfmt-vscode",
"ryu1kn.partial-diff",
"jeffersonlicet.snipped"
]
}

597
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,597 @@
{
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"explorer.fileNesting.patterns": {
".gitignore": ".gitattributes, .envrc, readme",
"flake.nix": "flake.lock, *.nix"
},
"files.exclude": {
".git-crypt": true
},
"terminal.integrated.defaultProfile.linux": "fish-fhs",
"terminal.integrated.profiles.linux": {
"fish-fhs": {
"args": [
"--user",
"--pty",
"--quiet",
"--same-dir",
"--service-type=exec",
"fish"
],
"path": "systemd-run"
}
},
"highlight.regex.regexes": [
{
"languageIds": [
"css",
"fish",
"go",
"java",
"javascript",
"jsonc",
"nix",
"postcss",
"rust",
"shellscript",
"svelte",
"typescript",
"yuck"
],
"regexes": [
{
"decorations": [
{
"backgroundColor": "#4ebbff99",
"isWholeLine": true,
"overviewRulerColor": "#4ebbff"
}
],
"regex": "(<|</)(script)(.*)",
"regexes": [
{
"decorations": [
{
"color": "#4ebbff"
}
],
"regex": "[</>]"
},
{
"decorations": [
{
"color": "#ffa07a"
}
],
"regex": "script"
}
],
"regexFlag": "gm"
},
{
"decorations": [
{
"backgroundColor": "#ffa07a99",
"isWholeLine": true,
"overviewRulerColor": "#ffa07a"
}
],
"regex": "(<|</)(style)(.*)",
"regexes": [
{
"decorations": [
{
"color": "#ffa07a"
}
],
"regex": "[</>]"
},
{
"decorations": [
{
"color": "#7ad9ff"
}
],
"regex": "style"
}
],
"regexFlag": "gm"
},
{
"regex": "(/\\*|<\\!--)(.|[\r\n])*?((\\*/|-->)|-->)",
"regexes": [
{
"decorations": [
{
"color": "#d4be98",
"fontWeight": "bold",
"index": 0
}
],
"regex": "\\B:D"
},
{
"decorations": [
{
"color": "#f00",
"fontWeight": "bold",
"index": 0
}
],
"regex": "\\!\\!\\!"
},
{
"decorations": [
{
"color": "#D8A657",
"fontWeight": "bold",
"index": 0
}
],
"regex": "\\^\\^"
},
{
"decorations": [
{
"color": "#E78A4E",
"fontWeight": "bold",
"index": 1
},
{
"color": "#D3869B",
"fontWeight": "bold",
"index": 2
}
],
"regex": "(<)(>)"
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#804600",
"color": "#d4be98",
"index": 1,
"overviewRulerColor": "#804600"
}
],
"regex": "(.*TODO:)((.|\\r|\\n)*?(\\*/|-->)$)",
"regexes": [
{
"decorations": [
{
"index": 0
},
{
"backgroundColor": "#80460099",
"color": "#d4be98",
"index": 2,
"overviewRulerColor": "#80460099"
}
],
"index": 2,
"regex": "([\\s]+)?( .*)"
}
]
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#fffacd",
"color": "#282828",
"index": 1,
"overviewRulerColor": "#fffacd"
}
],
"regex": "(.*NOTE:)((.|\\r|\\n)*?(\\*/|-->)$)",
"regexes": [
{
"decorations": [
{
"index": 0
},
{
"backgroundColor": "#fffacd99",
"color": "#282828",
"index": 2,
"overviewRulerColor": "#fffacd99"
}
],
"index": 2,
"regex": "([\\s]+)?( .*)"
}
]
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#6495ed",
"color": "#282828",
"index": 1,
"overviewRulerColor": "#6495ed"
}
],
"regex": "(.*IDEA:)((.|\\r|\\n)*?(\\*/|-->)$)",
"regexes": [
{
"decorations": [
{
"index": 0
},
{
"backgroundColor": "#6495ed99",
"color": "#282828",
"index": 2,
"overviewRulerColor": "#6495ed99"
}
],
"index": 2,
"regex": "([\\s]+)?( .*)"
}
]
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#66cc99",
"color": "#282828",
"index": 1,
"overviewRulerColor": "#66cc99"
}
],
"regex": "(.*INFO:)((.|\\r|\\n)*?(\\*/|-->)$)",
"regexes": [
{
"decorations": [
{
"index": 0
},
{
"backgroundColor": "#66cc9999",
"color": "#282828",
"index": 2,
"overviewRulerColor": "#66cc9999"
}
],
"index": 2,
"regex": "([\\s]+)?( .*)"
}
]
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#591d77",
"color": "#d4be98",
"index": 1,
"overviewRulerColor": "#591d77"
}
],
"regex": "(.*(?:ABOUT|EXP|\\?+):)((.|\\r|\\n)*?(\\*/|-->)$)",
"regexes": [
{
"decorations": [
{
"index": 0
},
{
"backgroundColor": "#591d7799",
"color": "#d4be98",
"index": 2,
"overviewRulerColor": "#591d7799"
}
],
"index": 2,
"regex": "([\\s]+)?( .*)"
}
]
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#a74165",
"color": "#d4be98",
"index": 1,
"overviewRulerColor": "#a74165"
}
],
"regex": "(.*(?:FIXME|FIX|BUG|DEBUG|HACK|REMOVE):)((.|\\r|\\n)*?(\\*/|-->)$)",
"regexes": [
{
"decorations": [
{
"index": 0
},
{
"backgroundColor": "#a7416599",
"color": "#d4be98",
"index": 2,
"overviewRulerColor": "#a7416599"
}
],
"index": 2,
"regex": "([\\s]+)?( .*)"
}
]
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#c36c5c",
"color": "#d4be98",
"index": 1,
"overviewRulerColor": "#c36c5c"
}
],
"regex": "(.*(?:SKELETON|COMPONENT):)((.|\\r|\\n)*?(\\*/|-->)$)",
"regexes": [
{
"decorations": [
{
"index": 0
},
{
"backgroundColor": "#c36c5c99",
"color": "#d4be98",
"index": 2,
"overviewRulerColor": "#c36c5c99"
}
],
"index": 2,
"regex": "([\\s]+)?( .*)"
}
]
}
],
"regexFlag": "gm",
"regexLimit": 25000
},
{
"regex": "(?<=\\s*)(//|#|;)(.|\r\n)*?$",
"regexes": [
{
"decorations": [
{
"color": "#d4be98",
"fontWeight": "bold",
"index": 0
}
],
"regex": "\\B:D"
},
{
"decorations": [
{
"fontWeight": "bold",
"index": 0
},
{
"color": "#D8A657",
"index": 1
},
{
"color": "#d4be98",
"index": 2
},
{
"color": "#d4be98",
"index": 4
},
{
"color": "#D8A657",
"index": 5
}
],
"regex": "(^/|#|;)(/|#|;)(.*)(/|#|;)(/|#|;$)"
},
{
"decorations": [
{
"color": "#f00",
"fontWeight": "bold",
"index": 0
}
],
"regex": "\\!\\!\\!"
},
{
"decorations": [
{
"color": "#D8A657",
"fontWeight": "bold",
"index": 0
}
],
"regex": "\\^\\^"
},
{
"decorations": [
{
"color": "#E78A4E",
"fontWeight": "bold",
"index": 1
},
{
"color": "#D3869B",
"fontWeight": "bold",
"index": 2
}
],
"regex": "(<)(>)"
},
{
"decorations": [
{
"color": "#d4be98",
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#804600",
"index": 1,
"overviewRulerColor": "#804600"
},
{
"backgroundColor": "#80460099",
"index": 2,
"overviewRulerColor": "#80460099"
}
],
"regex": "(.*TODO:)(.*)"
},
{
"decorations": [
{
"color": "#282828",
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#fffacd",
"index": 1,
"overviewRulerColor": "#fffacd"
},
{
"backgroundColor": "#fffacd99",
"index": 2,
"overviewRulerColor": "#fffacd99"
}
],
"regex": "(.*NOTE:)(.*)"
},
{
"decorations": [
{
"color": "#282828",
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#6495ed",
"index": 1,
"overviewRulerColor": "#6495ed"
},
{
"backgroundColor": "#6495ed99",
"index": 2,
"overviewRulerColor": "#6495ed99"
}
],
"regex": "(.*IDEA:)(.*)"
},
{
"decorations": [
{
"color": "#282828",
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#66cc99",
"index": 1,
"overviewRulerColor": "#66cc99"
},
{
"backgroundColor": "#66cc9999",
"index": 2,
"overviewRulerColor": "#66cc9999"
}
],
"regex": "(.*INFO:)(.*)"
},
{
"decorations": [
{
"color": "#d4be98",
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#591d77",
"index": 1,
"overviewRulerColor": "#591d77"
},
{
"backgroundColor": "#591d7799",
"index": 2,
"overviewRulerColor": "#591d7799"
}
],
"regex": "(.*(?:ABOUT|EXP|\\?+):)(.*)"
},
{
"decorations": [
{
"color": "#d4be98",
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#a74165",
"index": 1,
"overviewRulerColor": "#a74165"
},
{
"backgroundColor": "#a7416599",
"index": 2,
"overviewRulerColor": "#a7416599"
}
],
"regex": "(.*(?:FIXME|FIX|BUG|DEBUG|HACK|REMOVE):)(.*)"
},
{
"decorations": [
{
"color": "#d4be98",
"fontWeight": "bold",
"index": 0
},
{
"backgroundColor": "#c36c5c",
"index": 1,
"overviewRulerColor": "#c36c5c"
},
{
"backgroundColor": "#c36c5c99",
"index": 2,
"overviewRulerColor": "#c36c5c99"
}
],
"regex": "(.*(?:SKELETON|COMPONENT):)(.*)"
}
],
"regexFlag": "gm",
"regexLimit": 25000
}
]
}
]
}

61
flake.nix Normal file
View file

@ -0,0 +1,61 @@
{
description = "Wayming - Gaming setup for Wayland with configurable options and working defaults";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
chaotic.url = "github:chaotic-cx/nyx/nyxpkgs-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{
self,
nixpkgs,
home-manager,
flake-utils,
chaotic,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ self.overlays.default ];
};
# Extend lib with wayming utilities
lib = nixpkgs.lib.extend (
final: prev: {
wayming = import ./lib { lib = final; };
}
);
in
{
packages = {
proton-cachyos = pkgs.callPackage ./pkgs/proton-cachyos { };
default = self.packages.${system}.proton-cachyos;
};
# Expose the extended lib
lib = lib;
}
)
// {
homeManagerModules.wayming = import ./modules/home-manager.nix;
nixosModules.wayming = import ./modules/nixos.nix;
# Default module (home-manager)
homeManagerModules.default = self.homeManagerModules.wayming;
# Overlay for packages
overlays.default = final: prev: {
proton-cachyos = final.callPackage ./pkgs/proton-cachyos { };
# Add other packages here as needed
};
};
}

53
lib/defualt.nix Normal file
View file

@ -0,0 +1,53 @@
{ lib }:
{
# Helper to convert Nix attrs to gamescope command-line arguments
toCliArgs =
attrs:
let
argToString =
name: value:
if builtins.isBool value then
lib.optionalString value "--${name}"
else
"--${name} ${toString value}";
in
lib.concatStringsSep " " (lib.mapAttrsToList argToString attrs);
# Helper to convert Nix attrs to fish 'set -x' commands
toEnvCommands =
attrs:
lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: value: "set -x ${name} '${toString value}'") attrs
);
getPrimaryMonitor = monitors: lib.findFirst (m: m.primary) null monitors;
getMonitorDefaults = monitors: {
WIDTH =
let
pm = lib.wayming.getPrimaryMonitor monitors;
in
if pm != null then pm.width else 1920;
HEIGHT =
let
pm = lib.wayming.getPrimaryMonitor monitors;
in
if pm != null then pm.height else 1080;
REFRESH_RATE =
let
pm = lib.wayming.getPrimaryMonitor monitors;
in
if pm != null then pm.refreshRate else 60;
VRR =
let
pm = lib.wayming.getPrimaryMonitor monitors;
in
if pm != null then pm.vrr else false;
HDR =
let
pm = lib.wayming.getPrimaryMonitor monitors;
in
if pm != null then pm.hdr else false;
};
}

6
modules/home/default.nix Normal file
View file

@ -0,0 +1,6 @@
{
imports = [
./monitors.nix
./gamescoperun.nix
./wrappers.nix
];

View file

@ -0,0 +1,207 @@
{
lib,
config,
pkgs,
inputs,
...
}:
let
cfg = config.wayming.gamescoperun;
# Use shared lib functions
inherit (lib.wayming) toCliArgs toEnvCommands getMonitorDefaults;
# Get monitor defaults
monitorDefaults = getMonitorDefaults config.wayming.monitors;
inherit (monitorDefaults)
WIDTH
HEIGHT
REFRESH_RATE
VRR
HDR
;
# Select gamescope packages based on useGit option
gamescopePackages =
if cfg.useGit then
{
gamescope = inputs.chaotic.legacyPackages.${pkgs.system}.gamescope_git;
gamescope-wsi = inputs.chaotic.legacyPackages.${pkgs.system}.gamescope-wsi_git;
}
else
{
gamescope = pkgs.gamescope;
gamescope-wsi = pkgs.gamescope-wsi or null;
};
# Base options with monitor-derived defaults
defaultBaseOptions =
{
backend = "sdl";
fade-out-duration = 200;
fullscreen = true;
immediate-flips = true;
nested-refresh = REFRESH_RATE;
output-height = HEIGHT;
output-width = WIDTH;
rt = true;
}
// lib.optionalAttrs HDR {
hdr-enabled = true;
hdr-debug-force-output = true;
hdr-itm-enable = true;
}
// lib.optionalAttrs VRR {
adaptive-sync = true;
};
# Merge user options with defaults
finalBaseOptions = defaultBaseOptions // cfg.baseOptions;
defaultEnvironment =
{
ENABLE_GAMESCOPE_WSI = 1;
GAMESCOPE_WAYLAND_DISPLAY = "gamescope-0";
PROTON_USE_SDL = 1;
PROTON_USE_WAYLAND = 1;
SDL_VIDEODRIVER = "wayland";
AMD_VULKAN_ICD = "RADV";
RADV_PERFTEST = "aco";
DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1 = 1;
DISABLE_LAYER_NV_OPTIMUS_1 = 1;
}
// lib.optionalAttrs HDR {
ENABLE_HDR_WSI = 1;
DXVK_HDR = 1;
PROTON_ENABLE_HDR = 1;
};
# Merge user environment with defaults
finalEnvironment = defaultEnvironment // cfg.environment;
# The gamescoperun script
gamescoperun = pkgs.writeScriptBin "gamescoperun" ''
#!${lib.getExe pkgs.fish}
# Check if we're already inside a Gamescope session
if set -q GAMESCOPE_WAYLAND_DISPLAY
echo "Already inside Gamescope session ($GAMESCOPE_WAYLAND_DISPLAY), running command directly..."
exec $argv
end
# Set environment variables for the gamescope session
${toEnvCommands finalEnvironment}
# Define and parse arguments using fish's built-in argparse
argparse -i 'x/extra-args=' -- $argv
if test $status -ne 0
exit 1
end
# Check if we have a command to run
if test (count $argv) -eq 0
echo "Usage: gamescoperun [-x|--extra-args \"<options>\"] <command> [args...]"
echo ""
echo "Examples:"
echo " gamescoperun heroic"
echo " gamescoperun -x \"--fsr-upscaling-sharpness 5\" steam"
echo " GAMESCOPE_EXTRA_OPTS=\"--fsr\" gamescoperun steam (legacy)"
exit 1
end
# Combine base args, extra args from CLI, and extra args from env (for legacy)
set -l final_args ${toCliArgs finalBaseOptions}
# Add args from -x/--extra-args flag, splitting the string into a list
if set -q _flag_extra_args
set -a final_args (string split ' ' -- $_flag_extra_args)
end
# For legacy support, add args from GAMESCOPE_EXTRA_OPTS if it exists
if set -q GAMESCOPE_EXTRA_OPTS
set -a final_args (string split ' ' -- $GAMESCOPE_EXTRA_OPTS)
end
# Show the command being executed
echo -e "\033[1;36m[gamescoperun]\033[0m Running: \033[1;34m${lib.getExe gamescopePackages.gamescope}\033[0m $final_args \033[1;32m--\033[0m $argv"
# Execute gamescope with the final arguments and the command
exec ${lib.getExe gamescopePackages.gamescope} $final_args -- $argv
'';
in
{
options.wayming.gamescoperun = {
enable = lib.mkEnableOption "gamescoperun, a wrapper for gamescope";
useGit = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Use git versions of gamescope from chaotic-nyx for latest features";
};
baseOptions = lib.mkOption {
type =
with lib.types;
attrsOf (oneOf [
str
int
bool
]);
default = { };
example = {
"fsr-upscaling" = true;
"output-width" = 2560;
};
description = ''
Base command-line options to always pass to gamescope.
Option names must match gamescope's flags exactly (e.g., "hdr-enabled").
Monitor-derived options (width, height, refresh rate, HDR, VRR) are set automatically
but can be overridden here.
'';
};
environment = lib.mkOption {
type =
with lib.types;
attrsOf (oneOf [
str
int
]);
default = { };
description = ''
Environment variables to set within the gamescoperun script.
HDR-related variables are set automatically based on monitor configuration
but can be overridden here.
'';
};
package = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = gamescoperun;
description = "The configured gamescoperun package";
};
};
config = lib.mkIf cfg.enable {
# Install both gamescope and gamescope-wsi
home.packages =
[ cfg.package ]
++ [ gamescopePackages.gamescope ]
++ lib.optionals (gamescopePackages.gamescope-wsi != null) [ gamescopePackages.gamescope-wsi ];
# Assertion to ensure monitors are configured if gamescoperun is enabled
assertions = [
{
assertion = cfg.enable -> (lib.length config.wayming.monitors > 0);
message = "wayming.gamescoperun requires at least one monitor to be configured in wayming.monitors";
}
{
assertion = cfg.enable -> (lib.length (lib.filter (m: m.primary) config.wayming.monitors) == 1);
message = "wayming.gamescoperun requires exactly one primary monitor to be configured";
}
];
};
}

73
modules/home/monitors.nix Normal file
View file

@ -0,0 +1,73 @@
{ lib, config, ... }:
{
options.wayming.monitors = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
example = "DP-1";
};
primary = lib.mkOption {
type = lib.types.bool;
default = false;
};
width = lib.mkOption {
type = lib.types.int;
example = 1920;
};
height = lib.mkOption {
type = lib.types.int;
example = 1080;
};
refreshRate = lib.mkOption {
type = lib.types.int;
default = 60;
};
x = lib.mkOption {
type = lib.types.int;
default = 0;
};
y = lib.mkOption {
type = lib.types.int;
default = 0;
};
scale = lib.mkOption {
type = lib.types.number;
default = 1.0;
};
transform = lib.mkOption {
type = lib.types.int;
default = 0;
description = "Screen orientation: 0 = landscape, 1 = portrait left, 2 = portrait right, 3 = landscape flipped";
};
enabled = lib.mkOption {
type = lib.types.bool;
default = true;
};
hdr = lib.mkOption {
type = lib.types.bool;
default = false;
};
vrr = lib.mkOption {
type = lib.types.bool;
description = "Variable Refresh Rate aka Adaptive Sync aka AMD FreeSync.";
default = false;
};
};
}
);
default = [ ];
};
config = {
assertions = [
{
assertion =
((lib.length config.wayming.monitors) != 0)
-> ((lib.length (lib.filter (m: m.primary) config.wayming.monitors)) == 1);
message = "Exactly one monitor must be set to primary.";
}
];
};
}

118
modules/home/wrapper.nix Normal file
View file

@ -0,0 +1,118 @@
{
lib,
config,
pkgs,
...
}:
let
cfg = config.wayming.wrappers;
# Use shared lib function
inherit (lib.wayming) toCliArgs;
# Function to create a wrapper for an application
mkWrapper =
name: wrapperCfg:
let
# Get the original package
originalPackage = wrapperCfg.package;
# Create environment variable exports
envExports = lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: value: "set -x ${name} '${toString value}'") wrapperCfg.environment
);
# Convert extraOptions to CLI args
extraArgs = lib.optionalString (
wrapperCfg.extraOptions != { }
) "-x \"${toCliArgs wrapperCfg.extraOptions}\"";
# The wrapper script
wrapperScript = pkgs.writeScriptBin name ''
#!${lib.getExe pkgs.fish}
# Set additional environment variables
${envExports}
# Execute with gamescoperun
exec ${lib.getExe config.wayming.gamescoperun.package} ${extraArgs} ${lib.getExe originalPackage} $argv
'';
in
wrapperScript;
in
{
options.wayming.wrappers = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
enable = lib.mkEnableOption "wrapper for this application";
package = lib.mkOption {
type = lib.types.package;
description = "The package to wrap";
};
extraOptions = lib.mkOption {
type =
with lib.types;
attrsOf (oneOf [
str
int
bool
]);
default = { };
example = {
"fsr-upscaling" = true;
"force-windows-fullscreen" = true;
"fsr-upscaling-sharpness" = 5;
};
description = ''
Additional gamescope command-line options for this specific wrapper.
Option names must match gamescope's flags exactly (e.g., "hdr-enabled").
These will be passed via the -x flag to gamescoperun.
'';
};
environment = lib.mkOption {
type =
with lib.types;
attrsOf (oneOf [
str
int
]);
default = { };
example = {
STEAM_FORCE_DESKTOPUI_SCALING = 1;
STEAM_GAMEPADUI = 1;
};
description = "Additional environment variables for this specific wrapper";
};
# Readonly package option that exposes the configured wrapper
wrappedPackage = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = mkWrapper name config.wayming.wrappers.${name};
description = "The configured wrapper package for this application";
};
};
}
)
);
default = { };
description = "Application wrappers that run through gamescoperun";
};
config = {
home.packages = lib.mapAttrsToList mkWrapper (
lib.filterAttrs (name: wrapperCfg: wrapperCfg.enable) cfg
);
# Ensure gamescoperun is enabled if any wrappers are enabled
wayming.gamescoperun.enable = lib.mkIf (lib.length (lib.attrNames cfg) > 0) true;
};
}

32
modules/nixos/amd.nix Normal file
View file

@ -0,0 +1,32 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.wayming.amd;
in
{
options.wayming.amd = {
enable = lib.mkEnableOption "AMD GPU configuration with LACT (Linux AMD Control Tool)";
};
config = lib.mkIf cfg.enable {
# Enable graphics with 32-bit support for gaming
hardware.graphics = {
enable = lib.mkDefault true;
enable32Bit = lib.mkDefault true;
};
# Install LACT for AMD GPU control
environment.systemPackages = with pkgs; [ lact ];
# Enable LACT daemon
systemd = {
packages = with pkgs; [ lact ];
services.lactd.wantedBy = [ "multi-user.target" ];
};
};
}

47
modules/nixos/ananicy.nix Normal file
View file

@ -0,0 +1,47 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.wayming.ananicy;
# Default extra rules for gaming processes
defaultExtraRules = [
{
"name" = "gamescope";
"nice" = -20;
}
];
# Combine defaults with user extras
finalExtraRules = defaultExtraRules ++ cfg.extraRules;
in
{
options.wayming.ananicy = {
enable = lib.mkEnableOption "ananicy process scheduler optimization";
extraRules = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
default = [ ];
example = [
{
"name" = "steam";
"nice" = -10;
}
];
description = "Additional ananicy rules for gaming processes (added to defaults)";
};
};
config = lib.mkIf cfg.enable {
services.ananicy = {
enable = true;
package = lib.mkDefault pkgs.ananicy-cpp;
rulesProvider = lib.mkDefault pkgs.ananicy-cpp;
extraRules = finalExtraRules;
};
};
}

View file

@ -0,0 +1,9 @@
{
imports = [
./amd.nix
./ananicy.nix
./gamemode.nix
./lutris.nix
./steam.nix
];
}

View file

@ -0,0 +1,43 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.wayming.gamemode;
in
{
options.wayming.gamemode = {
enable = lib.mkEnableOption "gamemode configuration for gaming optimization";
settings = lib.mkOption {
type = lib.types.attrs;
default = {
general = {
softrealtime = "auto";
inhibit_screensaver = 1;
renice = 15;
};
gpu = {
apply_gpu_optimisations = "accept-responsibility";
gpu_device = 1;
amd_performance_level = "high";
};
custom = {
start = "${pkgs.libnotify}/bin/notify-send 'GameMode started'";
end = "${pkgs.libnotify}/bin/notify-send 'GameMode ended'";
};
};
description = "Gamemode configuration settings";
};
};
config = lib.mkIf cfg.enable {
programs.gamemode = {
enable = true;
settings = cfg.settings;
};
};
}

49
modules/nixos/lutris.nix Normal file
View file

@ -0,0 +1,49 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.wayming.lutris;
# Default extra packages
defaultExtraPkgs = with pkgs; [
wineWowPackages.waylandFull
winetricks
vulkan-tools
xterm
];
# Create the configured lutris package
configuredLutris = pkgs.lutris.override {
extraPkgs = pkgs: defaultExtraPkgs ++ cfg.extraPkgs;
};
in
{
options.wayming.lutris = {
enable = lib.mkEnableOption "Install Lutris game manager";
extraPkgs = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
example = with pkgs; [
mangohud
gamemode
];
description = "Additional extra packages for Lutris runtime (added to defaults)";
};
package = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = configuredLutris;
description = "The configured Lutris package with extra packages";
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
};
}

85
modules/nixos/steam.nix Normal file
View file

@ -0,0 +1,85 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.wayming.steam;
# Default compatibility packages
defaultCompatPackages = with pkgs; [
proton-ge-custom
proton-cachyos
];
# Combine defaults with user extras
finalCompatPackages = defaultCompatPackages ++ cfg.extraCompatPackages;
# Create the configured steam package
configuredSteam = pkgs.steam.override {
extraPkgs = cfg.extraPkgs;
};
in
{
options.wayming.steam = {
enable = lib.mkEnableOption "Steam with gaming optimizations";
extraCompatPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
example = with pkgs; [ proton-ge-bin ];
description = "Additional Proton compatibility packages to add to the defaults";
};
extraPkgs = lib.mkOption {
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default =
pkgs: with pkgs; [
# X11 libraries
xorg.libXcursor
xorg.libXi
xorg.libXinerama
xorg.libXScrnSaver
# System libraries
stdenv.cc.cc.lib
gamemode
gperftools
keyutils
libkrb5
libpng
libpulseaudio
libvorbis
mangohud
];
description = "Extra packages to include in Steam's runtime";
};
package = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = configuredSteam;
description = "The configured Steam package with extra packages";
};
};
config = lib.mkIf cfg.enable {
programs.steam = {
enable = true;
remotePlay.openFirewall = lib.mkDefault false;
dedicatedServer.openFirewall = lib.mkDefault false;
protontricks = {
enable = lib.mkDefault true;
package = lib.mkDefault pkgs.protontricks;
};
package = lib.mkDefault cfg.package;
# Use the combined list of default + user extras
extraCompatPackages = finalCompatPackages;
};
};
}

View file

@ -0,0 +1,47 @@
{
callPackage,
stdenv,
lib,
fetchurl,
}:
let
protonGeTitle = "Proton-CachyOS";
protonGeVersions = lib.importJSON ./versions.json;
in
stdenv.mkDerivation {
name = "proton-cachyos";
version = "${protonGeVersions.base}.${protonGeVersions.release}";
src =
let
tagName = "cachyos-${protonGeVersions.base}-${protonGeVersions.release}-slr";
fileName = "proton-cachyos-${protonGeVersions.base}-${protonGeVersions.release}-slr-x86_64.tar.xz";
in
fetchurl {
url = "https://github.com/CachyOS/proton-cachyos/releases/download/${tagName}/${fileName}";
inherit (protonGeVersions) hash;
};
buildCommand =
''
mkdir -p $out/bin
tar -C $out/bin --strip=1 -x -f $src
''
# Replace the internal name and display name
+ lib.strings.optionalString (protonGeTitle != null) ''
sed -i -r 's|"proton-cachyos-[^"]*"|"${protonGeTitle}"|g' $out/bin/compatibilitytool.vdf
sed -i -r 's|"display_name"[[:space:]]*"[^"]*"|"display_name" "${protonGeTitle}"|' $out/bin/compatibilitytool.vdf
'';
passthru.updateScript = callPackage ./update.nix { };
meta = with lib; {
description = "Compatibility tool for Steam Play based on Wine and additional components. CachyOS fork.";
homepage = "https://github.com/CachyOS/proton-cachyos";
license = licenses.bsd3;
platforms = [ "x86_64-linux" ];
maintainers = with maintainers; [
tophc7
];
};
}

View file

@ -0,0 +1,55 @@
{
writeShellScript,
lib,
coreutils,
findutils,
gnugrep,
curl,
jq,
git,
nix,
nix-prefetch-git,
moreutils,
yq,
}:
let
path = lib.makeBinPath [
coreutils
curl
findutils
gnugrep
jq
moreutils
git
nix-prefetch-git
nix
yq
];
in
writeShellScript "update-proton-cachyos" ''
set -euo pipefail
PATH=${path}
srcJson=pkgs/proton-cachyos/versions.json
localBase=$(jq -r .base < $srcJson)
localRelease=$(jq -r .release < $srcJson)
latestVer=$(curl 'https://github.com/GloriousEggroll/proton-cachyos/tags.atom' | xq -r '.feed.entry[0].link."@href"' | grep -Po '(?<=/)[^/]+$')
if [ "GE-Proton''${localBase}-''${localRelease}" == "$latestVer" ]; then
exit 0
fi
latestBase=$(echo $latestVer | grep -Po '(?<=GE-Proton)[^-]+')
latestRelease=$(echo $latestVer | grep -Po '(?<=-)[^-]+$')
latestSha256=$(nix-prefetch-url --type sha256 "https://github.com/CachyOS/proton-cachyos/releases/download/''${latestVer}/''${latestVer}.tar.gz")
latestHash=$(nix-hash --to-sri --type sha256 $latestSha256)
jq \
--arg latestBase "$latestBase" --arg latestRelease "$latestRelease" --arg latestHash "$latestHash" \
'.base = $latestBase | .release = $latestRelease | .hash = $latestHash' \
"$srcJson" | sponge "$srcJson"
git add $srcJson
git commit -m "proton-cachyos: ''${localBase}.''${localRelease} -> ''${latestBase}.''${latestRelease}"
''

View file

@ -0,0 +1,5 @@
{
"base": "10.0",
"release": "20250623",
"hash": "sha256-HLWWR2h+AdGfqt3Aay9Xyz7Q06NRoi3/Mp5vJtoqLlg="
}