From 6b701637ad308513b678c80baceec6c79e339ce9 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 17 Jul 2025 14:22:56 -0400 Subject: initial conf FE and BE hooks --- src/api/lsfgApi.ts | 4 +- src/components/ConfigurationSection.tsx | 67 ++++++---------- src/components/Content.tsx | 2 +- src/components/UsageInstructions.tsx | 130 ++++++++++++++------------------ src/config/configSchema.ts | 83 ++++++++------------ src/hooks/useLsfgHooks.ts | 2 +- 6 files changed, 113 insertions(+), 175 deletions(-) (limited to 'src') diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index f7363c1..8cdf6f0 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -76,14 +76,14 @@ export const getConfigSchema = callable<[], ConfigSchemaResult>("get_config_sche // Updated config function using centralized configuration export const updateLsfgConfig = callable< - [boolean, number, number, boolean, boolean, boolean, boolean, number], + [boolean, string, number, number, boolean, boolean], ConfigUpdateResult >("update_lsfg_config"); // Helper function to create config update from configuration object export const updateLsfgConfigFromObject = async (config: ConfigurationData): Promise => { const args = ConfigurationManager.createArgsFromConfig(config); - return updateLsfgConfig(...args as [boolean, number, number, boolean, boolean, boolean, boolean, number]); + return updateLsfgConfig(...args as [boolean, string, number, number, boolean, boolean]); }; // Self-updater API functions diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 2545217..118b418 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -1,9 +1,9 @@ -import { PanelSectionRow, ToggleField, SliderField } from "@decky/ui"; +import { PanelSectionRow, ToggleField, SliderField, TextField } from "@decky/ui"; import { ConfigurationData } from "../config/configSchema"; interface ConfigurationSectionProps { config: ConfigurationData; - onConfigChange: (fieldName: keyof ConfigurationData, value: boolean | number) => Promise; + onConfigChange: (fieldName: keyof ConfigurationData, value: boolean | number | string) => Promise; } export function ConfigurationSection({ @@ -30,16 +30,25 @@ export function ConfigurationSection({ onConfigChange('enable_lsfg', value)} + description="enable/disable lsfg on every game" + checked={config.enable} + onChange={(value) => onConfigChange('enable', value)} + /> + + + + onConfigChange('dll', e.target.value)} /> - - onConfigChange('hdr', value)} - /> - - onConfigChange('perf_mode', value)} + description="toggle performance mode (2x-8x performance increase)" + checked={config.performance_mode} + onChange={(value) => onConfigChange('performance_mode', value)} /> onConfigChange('immediate_mode', value)} - /> - - - - onConfigChange('frame_cap', value)} + label="HDR Mode" + description="enable hdr mode (doesn't support scrgb)" + checked={config.hdr_mode} + onChange={(value) => onConfigChange('hdr_mode', value)} /> - - {/* - onConfigChange('disable_vkbasalt', value)} - /> - */} ); } diff --git a/src/components/Content.tsx b/src/components/Content.tsx index ea3f3c1..613e722 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -37,7 +37,7 @@ export function Content() { }, [isInstalled, loadLsfgConfig]); // Generic configuration change handler - const handleConfigChange = async (fieldName: keyof ConfigurationData, value: boolean | number) => { + const handleConfigChange = async (fieldName: keyof ConfigurationData, value: boolean | number | string) => { await updateField(fieldName, value); }; diff --git a/src/components/UsageInstructions.tsx b/src/components/UsageInstructions.tsx index 727a0ab..ac721c7 100644 --- a/src/components/UsageInstructions.tsx +++ b/src/components/UsageInstructions.tsx @@ -6,88 +6,68 @@ interface UsageInstructionsProps { } export function UsageInstructions({ config }: UsageInstructionsProps) { - // Build manual environment variables string based on current config - const buildManualEnvVars = (): string => { - const envVars: string[] = []; - - if (config.enable_lsfg) { - envVars.push("ENABLE_LSFG=1"); - } - - // Always include multiplier and flow_scale if LSFG is enabled, as they have defaults - if (config.enable_lsfg) { - envVars.push(`LSFG_MULTIPLIER=${config.multiplier}`); - envVars.push(`LSFG_FLOW_SCALE=${config.flow_scale}`); - } - - if (config.hdr) { - envVars.push("LSFG_HDR=1"); - } - - if (config.perf_mode) { - envVars.push("LSFG_PERF_MODE=1"); - } - - if (config.immediate_mode) { - envVars.push("MESA_VK_WSI_PRESENT_MODE=immediate"); - } - - if (config.disable_vkbasalt) { - envVars.push("DISABLE_VKBASALT=1"); - } - - if (config.frame_cap > 0) { - envVars.push(`DXVK_FRAME_RATE=${config.frame_cap}`); - } - - return envVars.length > 0 ? `${envVars.join(" ")} %command%` : "%command%"; - }; - return ( <>
+ Usage Instructions +
+
+ + +
+ {config.enable + ? "LSFG is enabled globally. The layer will be active for all games automatically. No launch arguments needed." + : "LSFG is disabled. Enable it above to activate frame generation for all games." + } +
+
+ + +
+ {`Current Configuration: +• Enable: ${config.enable ? "Yes" : "No"} +• DLL Path: ${config.dll} +• Multiplier: ${config.multiplier}x +• Flow Scale: ${Math.round(config.flow_scale * 100)}% +• Performance Mode: ${config.performance_mode ? "Yes" : "No"} +• HDR Mode: ${config.hdr_mode ? "Yes" : "No"}`} +
+
+ + +
-
- Usage Instructions: -
-
- Option 1: Use the lsfg script (recommended): -
-
- ~/lsfg %command% -
-
- Option 2: Manual environment variables: -
-
- {buildManualEnvVars()} -
+ The configuration is stored in ~/.config/lsfg-vk/conf.toml and applies to all games globally.
diff --git a/src/config/configSchema.ts b/src/config/configSchema.ts index 6956030..83dc4aa 100644 --- a/src/config/configSchema.ts +++ b/src/config/configSchema.ts @@ -9,95 +9,72 @@ export enum ConfigFieldType { BOOLEAN = "boolean", INTEGER = "integer", - FLOAT = "float" + FLOAT = "float", + STRING = "string" } // Configuration field definition export interface ConfigField { name: string; fieldType: ConfigFieldType; - default: boolean | number; + default: boolean | number | string; description: string; - scriptTemplate: string; - scriptComment?: string; } // Configuration schema - must match Python CONFIG_SCHEMA export const CONFIG_SCHEMA: Record = { - enable_lsfg: { - name: "enable_lsfg", + enable: { + name: "enable", fieldType: ConfigFieldType.BOOLEAN, default: true, - description: "Enables the frame generation layer", - scriptTemplate: "export ENABLE_LSFG={value}", - scriptComment: "# export ENABLE_LSFG=1" + description: "enable/disable lsfg on every game" + }, + + dll: { + name: "dll", + fieldType: ConfigFieldType.STRING, + default: "/games/Lossless Scaling/Lossless.dll", + description: "specify where Lossless.dll is stored" }, multiplier: { name: "multiplier", fieldType: ConfigFieldType.INTEGER, default: 2, - description: "Traditional FPS multiplier value", - scriptTemplate: "export LSFG_MULTIPLIER={value}" + description: "change the fps multiplier" }, flow_scale: { name: "flow_scale", fieldType: ConfigFieldType.FLOAT, default: 0.8, - description: "Lowers the internal motion estimation resolution", - scriptTemplate: "export LSFG_FLOW_SCALE={value}" - }, - - hdr: { - name: "hdr", - fieldType: ConfigFieldType.BOOLEAN, - default: false, - description: "Enable HDR mode (only if Game supports HDR)", - scriptTemplate: "export LSFG_HDR={value}", - scriptComment: "# export LSFG_HDR=1" + description: "change the flow scale (lower = faster)" }, - perf_mode: { - name: "perf_mode", + performance_mode: { + name: "performance_mode", fieldType: ConfigFieldType.BOOLEAN, default: true, - description: "Use lighter model for FG", - scriptTemplate: "export LSFG_PERF_MODE={value}", - scriptComment: "# export LSFG_PERF_MODE=1" + description: "toggle performance mode (2x-8x performance increase)" }, - immediate_mode: { - name: "immediate_mode", + hdr_mode: { + name: "hdr_mode", fieldType: ConfigFieldType.BOOLEAN, default: false, - description: "Reduce input lag (Experimental, will cause issues in many games)", - scriptTemplate: "export MESA_VK_WSI_PRESENT_MODE=immediate # - disable vsync", - scriptComment: "# export MESA_VK_WSI_PRESENT_MODE=immediate # - disable vsync" - }, - - disable_vkbasalt: { - name: "disable_vkbasalt", - fieldType: ConfigFieldType.BOOLEAN, - default: true, - description: "Some plugins add vkbasalt layer, which can break lsfg. Toggling on fixes this", - scriptTemplate: "export DISABLE_VKBASALT={value}", - scriptComment: "# export DISABLE_VKBASALT=1" - }, - - frame_cap: { - name: "frame_cap", - fieldType: ConfigFieldType.INTEGER, - default: 0, - description: "Limit base game FPS (0 = disabled)", - scriptTemplate: "export DXVK_FRAME_RATE={value}", - scriptComment: "# export DXVK_FRAME_RATE=60" + description: "enable hdr mode (doesn't support scrgb)" } }; // Type-safe configuration data structure export interface ConfigurationData { - enable_lsfg: boolean; + enable: boolean; + dll: string; + multiplier: number; + flow_scale: number; + performance_mode: boolean; + hdr_mode: boolean; +} multiplier: number; flow_scale: number; hdr: boolean; @@ -140,7 +117,7 @@ export class ConfigurationManager { /** * Create ordered arguments array from configuration object */ - static createArgsFromConfig(config: ConfigurationData): (boolean | number)[] { + static createArgsFromConfig(config: ConfigurationData): (boolean | number | string)[] { return this.getFieldNames().map(fieldName => config[fieldName as keyof ConfigurationData] ); @@ -163,6 +140,8 @@ export class ConfigurationManager { (validated as any)[fieldName] = parseInt(String(value), 10); } else if (fieldDef.fieldType === ConfigFieldType.FLOAT) { (validated as any)[fieldName] = parseFloat(String(value)); + } else if (fieldDef.fieldType === ConfigFieldType.STRING) { + (validated as any)[fieldName] = String(value); } } }); diff --git a/src/hooks/useLsfgHooks.ts b/src/hooks/useLsfgHooks.ts index 8ff9061..e514d72 100644 --- a/src/hooks/useLsfgHooks.ts +++ b/src/hooks/useLsfgHooks.ts @@ -110,7 +110,7 @@ export function useLsfgConfig() { } }, []); - const updateField = useCallback(async (fieldName: keyof ConfigurationData, value: boolean | number): Promise => { + const updateField = useCallback(async (fieldName: keyof ConfigurationData, value: boolean | number | string): Promise => { const newConfig = { ...config, [fieldName]: value }; return updateConfig(newConfig); }, [config, updateConfig]); -- cgit v1.2.3 From ad0ba0fc61f83e2aaf22192e7d0ad05dde9ffd62 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 17 Jul 2025 14:53:18 -0400 Subject: fix descriptions and cleanup UI --- src/components/ConfigurationSection.tsx | 12 ++++++------ src/config/configSchema.ts | 14 +++----------- 2 files changed, 9 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 118b418..a1c175a 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -30,25 +30,25 @@ export function ConfigurationSection({ onConfigChange('enable', value)} /> - + {/* onConfigChange('dll', e.target.value)} /> - + */} onConfigChange('performance_mode', value)} /> @@ -87,7 +87,7 @@ export function ConfigurationSection({ onConfigChange('hdr_mode', value)} /> diff --git a/src/config/configSchema.ts b/src/config/configSchema.ts index 83dc4aa..6dc8687 100644 --- a/src/config/configSchema.ts +++ b/src/config/configSchema.ts @@ -48,21 +48,21 @@ export const CONFIG_SCHEMA: Record = { name: "flow_scale", fieldType: ConfigFieldType.FLOAT, default: 0.8, - description: "change the flow scale (lower = faster)" + description: "change the flow scale" }, performance_mode: { name: "performance_mode", fieldType: ConfigFieldType.BOOLEAN, default: true, - description: "toggle performance mode (2x-8x performance increase)" + description: "toggle performance mode" }, hdr_mode: { name: "hdr_mode", fieldType: ConfigFieldType.BOOLEAN, default: false, - description: "enable hdr mode (doesn't support scrgb)" + description: "enable hdr in games that support it" } }; @@ -75,14 +75,6 @@ export interface ConfigurationData { performance_mode: boolean; hdr_mode: boolean; } - multiplier: number; - flow_scale: number; - hdr: boolean; - perf_mode: boolean; - immediate_mode: boolean; - disable_vkbasalt: boolean; - frame_cap: number; -} // Centralized configuration manager export class ConfigurationManager { -- cgit v1.2.3 From f2870ff308131a0a4c970edf36bb88aac10a6175 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 17 Jul 2025 21:35:54 -0400 Subject: fix dll config write crash, add multiplier = 1 --- src/components/ConfigurationSection.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index a1c175a..deb8fba 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -48,16 +48,17 @@ export function ConfigurationSection({ onConfigChange('multiplier', value)} /> -- cgit v1.2.3 From 0670041467ca5625d93e3e4dbc2f738da24d88b4 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 17 Jul 2025 23:23:03 -0400 Subject: add experimental toggles --- src/api/lsfgApi.ts | 4 +-- src/components/ConfigurationSection.tsx | 46 ++++++++++++++++++++++++++++++++- src/components/Content.tsx | 4 +-- src/components/UsageInstructions.tsx | 4 ++- src/components/index.ts | 2 +- src/config/configSchema.ts | 16 ++++++++++++ 6 files changed, 69 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index 8cdf6f0..7d37f4e 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -76,14 +76,14 @@ export const getConfigSchema = callable<[], ConfigSchemaResult>("get_config_sche // Updated config function using centralized configuration export const updateLsfgConfig = callable< - [boolean, string, number, number, boolean, boolean], + [boolean, string, number, number, boolean, boolean, string, number], ConfigUpdateResult >("update_lsfg_config"); // Helper function to create config update from configuration object export const updateLsfgConfigFromObject = async (config: ConfigurationData): Promise => { const args = ConfigurationManager.createArgsFromConfig(config); - return updateLsfgConfig(...args as [boolean, string, number, number, boolean, boolean]); + return updateLsfgConfig(...args as [boolean, string, number, number, boolean, boolean, string, number]); }; // Self-updater API functions diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index deb8fba..76b9bc2 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -1,4 +1,4 @@ -import { PanelSectionRow, ToggleField, SliderField, TextField } from "@decky/ui"; +import { PanelSectionRow, ToggleField, SliderField, Dropdown } from "@decky/ui"; import { ConfigurationData } from "../config/configSchema"; interface ConfigurationSectionProps { @@ -93,6 +93,50 @@ export function ConfigurationSection({ onChange={(value) => onConfigChange('hdr_mode', value)} /> + + {/* Experimental Features Section */} + +
+ ⚠️ Experimental Features +
+
+ + + onConfigChange('experimental_present_mode', value.data)} + rgOptions={[ + { data: "", label: "Default (FIFO)" }, + { data: "fifo", label: "FIFO" }, + { data: "vsync", label: "VSync" }, + { data: "mailbox", label: "Mailbox" }, + { data: "immediate", label: "Immediate" } + ]} + /> + + + + 0 ? ` (${config.experimental_fps_limit} FPS)` : ' (Off)'}`} + description="Base framerate cap for DXVK games, before frame multiplier (0 = disabled)" + value={config.experimental_fps_limit} + min={0} + max={60} + step={1} + onChange={(value) => onConfigChange('experimental_fps_limit', value)} + /> + ); } diff --git a/src/components/Content.tsx b/src/components/Content.tsx index 613e722..ae64931 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -5,7 +5,7 @@ import { useInstallationActions } from "../hooks/useInstallationActions"; import { StatusDisplay } from "./StatusDisplay"; import { InstallationButton } from "./InstallationButton"; import { ConfigurationSection } from "./ConfigurationSection"; -import { UsageInstructions } from "./UsageInstructions"; +// import { UsageInstructions } from "./UsageInstructions"; import { WikiButton } from "./WikiButton"; import { ClipboardButton } from "./ClipboardButton"; import { PluginUpdateChecker } from "./PluginUpdateChecker"; @@ -74,7 +74,7 @@ export function Content() { /> )} - + {/* */} diff --git a/src/components/UsageInstructions.tsx b/src/components/UsageInstructions.tsx index ac721c7..d156f9d 100644 --- a/src/components/UsageInstructions.tsx +++ b/src/components/UsageInstructions.tsx @@ -54,7 +54,9 @@ export function UsageInstructions({ config }: UsageInstructionsProps) { • Multiplier: ${config.multiplier}x • Flow Scale: ${Math.round(config.flow_scale * 100)}% • Performance Mode: ${config.performance_mode ? "Yes" : "No"} -• HDR Mode: ${config.hdr_mode ? "Yes" : "No"}`} +• HDR Mode: ${config.hdr_mode ? "Yes" : "No"} +• Present Mode: ${config.experimental_present_mode || "Default (FIFO)"} +• FPS Limit: ${config.experimental_fps_limit > 0 ? `${config.experimental_fps_limit} FPS` : "Off"}`}
diff --git a/src/components/index.ts b/src/components/index.ts index d26159d..ab7a117 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -2,7 +2,7 @@ export { Content } from "./Content"; export { StatusDisplay } from "./StatusDisplay"; export { InstallationButton } from "./InstallationButton"; export { ConfigurationSection } from "./ConfigurationSection"; -export { UsageInstructions } from "./UsageInstructions"; +// export { UsageInstructions } from "./UsageInstructions"; export { WikiButton } from "./WikiButton"; export { ClipboardButton } from "./ClipboardButton"; export { PluginUpdateChecker } from "./PluginUpdateChecker"; diff --git a/src/config/configSchema.ts b/src/config/configSchema.ts index 6dc8687..9b6fc41 100644 --- a/src/config/configSchema.ts +++ b/src/config/configSchema.ts @@ -63,6 +63,20 @@ export const CONFIG_SCHEMA: Record = { fieldType: ConfigFieldType.BOOLEAN, default: false, description: "enable hdr in games that support it" + }, + + experimental_present_mode: { + name: "experimental_present_mode", + fieldType: ConfigFieldType.STRING, + default: "", + description: "experimental: override vulkan present mode (empty/fifo/vsync/mailbox/immediate)" + }, + + experimental_fps_limit: { + name: "experimental_fps_limit", + fieldType: ConfigFieldType.INTEGER, + default: 0, + description: "experimental: base framerate cap for dxvk games, before frame multiplier (0 = disabled)" } }; @@ -74,6 +88,8 @@ export interface ConfigurationData { flow_scale: number; performance_mode: boolean; hdr_mode: boolean; + experimental_present_mode: string; + experimental_fps_limit: number; } // Centralized configuration manager -- cgit v1.2.3 From a921fc8168e13934bdfe6d159aee14ee2651949e Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 17 Jul 2025 23:44:51 -0400 Subject: styling cleanup --- src/components/ConfigurationSection.tsx | 47 +++++++----- src/components/PluginUpdateChecker.tsx | 123 +++++++++++++++++++------------- 2 files changed, 105 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 76b9bc2..0ee605c 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -94,17 +94,16 @@ export function ConfigurationSection({ />
- {/* Experimental Features Section */}
⚠️ Experimental Features @@ -112,18 +111,34 @@ export function ConfigurationSection({ - onConfigChange('experimental_present_mode', value.data)} - rgOptions={[ - { data: "", label: "Default (FIFO)" }, - { data: "fifo", label: "FIFO" }, - { data: "vsync", label: "VSync" }, - { data: "mailbox", label: "Mailbox" }, - { data: "immediate", label: "Immediate" } - ]} - /> +
+
+ Override Vulkan present mode +
+
+ Select a specific Vulkan presentation mode for better performance or compatibility +
+ onConfigChange('experimental_present_mode', value.data)} + rgOptions={[ + { data: "", label: "Default (FIFO)" }, + { data: "fifo", label: "FIFO" }, + { data: "vsync", label: "VSync" }, + { data: "mailbox", label: "Mailbox" }, + { data: "immediate", label: "Immediate" } + ]} + /> +
diff --git a/src/components/PluginUpdateChecker.tsx b/src/components/PluginUpdateChecker.tsx index 0028a79..a3982c2 100644 --- a/src/components/PluginUpdateChecker.tsx +++ b/src/components/PluginUpdateChecker.tsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import { ButtonItem, - PanelSection + PanelSection, + PanelSectionRow } from '@decky/ui'; import { checkForPluginUpdate, downloadPluginUpdate, UpdateCheckResult, UpdateDownloadResult } from '../api/lsfgApi'; @@ -121,66 +122,90 @@ export const PluginUpdateChecker: React.FC = () => { }; return ( - - - {checkingUpdate ? 'Checking for updates...' : 'Check for Updates'} - + + +
+ PLUGIN UPDATES +
+
- {updateInfo && updateInfo.updateAvailable && !downloadResult?.success && ( + - {downloadingUpdate ? 'Downloading...' : 'Download Update'} + {checkingUpdate ? 'Checking for updates...' : 'Check for Updates'} + + + {updateInfo && updateInfo.updateAvailable && !downloadResult?.success && ( + + + {downloadingUpdate ? 'Downloading...' : 'Download Update'} + + )} {downloadResult?.success && ( -
-
- ✓ Download Complete! + +
+
+ ✓ Download Complete! +
+
+ File saved to: {downloadResult.download_path} +
+
+ Installation Instructions: +
    +
  1. Go to Decky Loader settings
  2. +
  3. Click "Developer" tab
  4. +
  5. Click "Uninstall" next to "Lossless Scaling"
  6. +
  7. Click "Install from ZIP"
  8. +
  9. Select the downloaded file
  10. +
  11. Restart Steam or reload plugins
  12. +
+
-
- File saved to: {downloadResult.download_path} -
-
- Installation Instructions: -
    -
  1. Go to Decky Loader settings
  2. -
  3. Click "Developer" tab
  4. -
  5. Click "Uninstall" next to "Lossless Scaling"
  6. -
  7. Click "Install from ZIP"
  8. -
  9. Select the downloaded file
  10. -
  11. Restart Steam or reload plugins
  12. -
-
-
+ )} {updateError && ( -
- {updateError} -
+ +
+ {updateError} +
+
)} ); -- cgit v1.2.3 From f74ce82fcebdcb11c190a1652277f8e08d9590f4 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 17 Jul 2025 23:51:05 -0400 Subject: persist plugin state --- src/components/Content.tsx | 4 ++-- src/components/index.ts | 2 +- src/index.tsx | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/components/Content.tsx b/src/components/Content.tsx index ae64931..b248313 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -7,7 +7,7 @@ import { InstallationButton } from "./InstallationButton"; import { ConfigurationSection } from "./ConfigurationSection"; // import { UsageInstructions } from "./UsageInstructions"; import { WikiButton } from "./WikiButton"; -import { ClipboardButton } from "./ClipboardButton"; +// import { ClipboardButton } from "./ClipboardButton"; import { PluginUpdateChecker } from "./PluginUpdateChecker"; import { ConfigurationData } from "../config/configSchema"; @@ -77,7 +77,7 @@ export function Content() { {/* */} - + {/* */} {/* Plugin Update Checker */} diff --git a/src/components/index.ts b/src/components/index.ts index ab7a117..ec4c194 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -4,5 +4,5 @@ export { InstallationButton } from "./InstallationButton"; export { ConfigurationSection } from "./ConfigurationSection"; // export { UsageInstructions } from "./UsageInstructions"; export { WikiButton } from "./WikiButton"; -export { ClipboardButton } from "./ClipboardButton"; +// export { ClipboardButton } from "./ClipboardButton"; export { PluginUpdateChecker } from "./PluginUpdateChecker"; diff --git a/src/index.tsx b/src/index.tsx index e8ab56f..785ecf5 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -11,6 +11,8 @@ export default definePlugin(() => { name: "Lossless Scaling", // The element displayed at the top of your plugin's menu titleView:
Lossless Scaling
, + // Always render to retain state when panel is toggled + alwaysRender: true, // The content of your plugin's menu content: , // The icon displayed in the plugin list -- cgit v1.2.3 From b04af8a2d32ca940e1c626090e13804fed7057c6 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Thu, 17 Jul 2025 23:59:15 -0400 Subject: updater styling alignment --- src/components/PluginUpdateChecker.tsx | 104 +++++++++++---------------------- 1 file changed, 34 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/components/PluginUpdateChecker.tsx b/src/components/PluginUpdateChecker.tsx index a3982c2..e7a9345 100644 --- a/src/components/PluginUpdateChecker.tsx +++ b/src/components/PluginUpdateChecker.tsx @@ -2,7 +2,9 @@ import React, { useState, useEffect } from 'react'; import { ButtonItem, PanelSection, - PanelSectionRow + PanelSectionRow, + Field, + Focusable } from '@decky/ui'; import { checkForPluginUpdate, downloadPluginUpdate, UpdateCheckResult, UpdateDownloadResult } from '../api/lsfgApi'; @@ -100,45 +102,17 @@ export const PluginUpdateChecker: React.FC = () => { if (updateInfo.updateAvailable) { if (downloadResult?.success) { - return ( -
- ✓ v{updateInfo.latestVersion} downloaded - ready to install -
- ); + return "✓ v" + updateInfo.latestVersion + " downloaded - ready to install"; } else { - return ( -
- Update available: v{updateInfo.latestVersion} -
- ); + return "Update available: v" + updateInfo.latestVersion; } } else { - return ( -
- Up to date (v{updateInfo.currentVersion}) -
- ); + return "Up to date (v" + updateInfo.currentVersion + ")"; } }; return ( - - -
- PLUGIN UPDATES -
-
- + = () => { )} {downloadResult?.success && ( - -
-
- ✓ Download Complete! -
-
- File saved to: {downloadResult.download_path} -
-
- Installation Instructions: -
    -
  1. Go to Decky Loader settings
  2. -
  3. Click "Developer" tab
  4. -
  5. Click "Uninstall" next to "Lossless Scaling"
  6. -
  7. Click "Install from ZIP"
  8. -
  9. Select the downloaded file
  10. -
  11. Restart Steam or reload plugins
  12. -
-
-
-
+ <> + + + + File saved to: {downloadResult.download_path} + + + + + + + + 1. Go to Decky Loader settings +
2. Click "Developer" tab +
3. Click "Uninstall" next to "Lossless Scaling" +
4. Click "Install from ZIP" +
5. Select the downloaded file +
6. Restart Steam or reload plugins +
+
+
+ )} {updateError && ( -
- {updateError} -
+ + + {updateError} + +
)}
-- cgit v1.2.3 From 14b08ac219dc134e130fc89b02c5a963d93bf243 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 00:06:11 -0400 Subject: fix experimental section formatting --- src/components/ConfigurationSection.tsx | 46 ++++++++++++--------------------- src/components/PluginUpdateChecker.tsx | 2 +- 2 files changed, 17 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 0ee605c..8433b04 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -1,4 +1,4 @@ -import { PanelSectionRow, ToggleField, SliderField, Dropdown } from "@decky/ui"; +import { PanelSectionRow, ToggleField, SliderField, DropdownItem } from "@decky/ui"; import { ConfigurationData } from "../config/configSchema"; interface ConfigurationSectionProps { @@ -106,39 +106,25 @@ export function ConfigurationSection({ color: "white" }} > - ⚠️ Experimental Features + Experimental Features
-
-
- Override Vulkan present mode -
-
- Select a specific Vulkan presentation mode for better performance or compatibility -
- onConfigChange('experimental_present_mode', value.data)} - rgOptions={[ - { data: "", label: "Default (FIFO)" }, - { data: "fifo", label: "FIFO" }, - { data: "vsync", label: "VSync" }, - { data: "mailbox", label: "Mailbox" }, - { data: "immediate", label: "Immediate" } - ]} - /> -
+ onConfigChange('experimental_present_mode', value.data)} + rgOptions={[ + { data: "", label: "Default (FIFO)" }, + { data: "fifo", label: "FIFO" }, + { data: "vsync", label: "VSync" }, + { data: "mailbox", label: "Mailbox" }, + { data: "immediate", label: "Immediate" } + ]} + />
diff --git a/src/components/PluginUpdateChecker.tsx b/src/components/PluginUpdateChecker.tsx index e7a9345..d427c18 100644 --- a/src/components/PluginUpdateChecker.tsx +++ b/src/components/PluginUpdateChecker.tsx @@ -140,7 +140,7 @@ export const PluginUpdateChecker: React.FC = () => { {downloadResult?.success && ( <> - + File saved to: {downloadResult.download_path} -- cgit v1.2.3 From 4ab2952d1b3bd5b87e9b9766c0b098f1b4885340 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 09:15:00 -0400 Subject: description tweak --- src/components/ConfigurationSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 8433b04..794a860 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -130,7 +130,7 @@ export function ConfigurationSection({ 0 ? ` (${config.experimental_fps_limit} FPS)` : ' (Off)'}`} - description="Base framerate cap for DXVK games, before frame multiplier (0 = disabled)" + description="Base framerate cap for DirectX games, before frame multiplier (0 = disabled)" value={config.experimental_fps_limit} min={0} max={60} -- cgit v1.2.3 From da113f878447e0830d414bb90b79b9a03d8cedec Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 09:17:16 -0400 Subject: fix label for multiplier --- src/components/ConfigurationSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 794a860..f44dd4f 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -55,7 +55,7 @@ export function ConfigurationSection({ step={1} notchCount={4} notchLabels={[ - { notchIndex: 0, label: "1X" }, + { notchIndex: 0, label: "OFF" }, { notchIndex: 1, label: "2X" }, { notchIndex: 2, label: "3X" }, { notchIndex: 3, label: "4X" } -- cgit v1.2.3 From 48ee73dae1bdecec47ccbaf5456be8c5937cb0fd Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 12:00:31 -0400 Subject: new profile method workaround for sudo global use --- src/api/lsfgApi.ts | 7 +++++++ src/components/ClipboardButton.tsx | 28 +++++++++++++++++++++++----- src/components/Content.tsx | 8 ++++---- src/components/LaunchOptionInfo.tsx | 25 +++++++++++++++++++++++++ src/components/UsageInstructions.tsx | 26 +++++++++++++++++++++++--- src/components/index.ts | 3 ++- 6 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 src/components/LaunchOptionInfo.tsx (limited to 'src') diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index 7d37f4e..5d866ef 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -66,6 +66,12 @@ export interface UpdateDownloadResult { error?: string; } +export interface LaunchOptionResult { + launch_option: string; + instructions: string; + explanation: string; +} + // API functions export const installLsfgVk = callable<[], InstallationResult>("install_lsfg_vk"); export const uninstallLsfgVk = callable<[], InstallationResult>("uninstall_lsfg_vk"); @@ -73,6 +79,7 @@ export const checkLsfgVkInstalled = callable<[], InstallationStatus>("check_lsfg export const checkLosslessScalingDll = callable<[], DllDetectionResult>("check_lossless_scaling_dll"); export const getLsfgConfig = callable<[], ConfigResult>("get_lsfg_config"); export const getConfigSchema = callable<[], ConfigSchemaResult>("get_config_schema"); +export const getLaunchOption = callable<[], LaunchOptionResult>("get_launch_option"); // Updated config function using centralized configuration export const updateLsfgConfig = callable< diff --git a/src/components/ClipboardButton.tsx b/src/components/ClipboardButton.tsx index 3760e81..cf11e6e 100644 --- a/src/components/ClipboardButton.tsx +++ b/src/components/ClipboardButton.tsx @@ -1,9 +1,26 @@ +import { useState } from "react"; import { PanelSectionRow, ButtonItem } from "@decky/ui"; -import { FaExternalLinkAlt } from "react-icons/fa"; +import { FaClipboard, FaCheck } from "react-icons/fa"; +import { getLaunchOption } from "../api/lsfgApi"; export function ClipboardButton() { - const handleClipboardClick = () => { - window.open("https://github.com/xXJSONDeruloXx/decky-lossless-scaling-vk/wiki/Clipboard", "_blank"); + const [copied, setCopied] = useState(false); + + const handleClipboardClick = async () => { + try { + // Get the launch option from the backend + const response = await getLaunchOption(); + const launchOption = response.launch_option; + + // Copy to clipboard + await navigator.clipboard.writeText(launchOption); + setCopied(true); + + // Reset the copied state after 2 seconds + setTimeout(() => setCopied(false), 2000); + } catch (error) { + console.error("Failed to copy launch option:", error); + } }; return ( @@ -11,10 +28,11 @@ export function ClipboardButton() {
- -
Launch Option Clipboard
+ {copied ? : } +
{copied ? "Copied!" : "Copy Launch Option"}
diff --git a/src/components/Content.tsx b/src/components/Content.tsx index b248313..613e722 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -5,9 +5,9 @@ import { useInstallationActions } from "../hooks/useInstallationActions"; import { StatusDisplay } from "./StatusDisplay"; import { InstallationButton } from "./InstallationButton"; import { ConfigurationSection } from "./ConfigurationSection"; -// import { UsageInstructions } from "./UsageInstructions"; +import { UsageInstructions } from "./UsageInstructions"; import { WikiButton } from "./WikiButton"; -// import { ClipboardButton } from "./ClipboardButton"; +import { ClipboardButton } from "./ClipboardButton"; import { PluginUpdateChecker } from "./PluginUpdateChecker"; import { ConfigurationData } from "../config/configSchema"; @@ -74,10 +74,10 @@ export function Content() { /> )} - {/* */} + - {/* */} + {/* Plugin Update Checker */} diff --git a/src/components/LaunchOptionInfo.tsx b/src/components/LaunchOptionInfo.tsx new file mode 100644 index 0000000..298c45a --- /dev/null +++ b/src/components/LaunchOptionInfo.tsx @@ -0,0 +1,25 @@ +import { PanelSectionRow, Field } from "@decky/ui"; + +export function LaunchOptionInfo() { + return ( + + +
For each game where you want to use lsfg-vk:
+
+ 1. Right-click the game in Steam → Properties
+ 2. Add this to Launch Options: LSFG_PROCESS=decky-lsfg-vk %command%
+ 3. Or use the "Copy Launch Option" button above +
+
+ This temporary solution allows hot-reloading while keeping you on the latest lsfg-vk version. +
+ + } + /> +
+ ); +} diff --git a/src/components/UsageInstructions.tsx b/src/components/UsageInstructions.tsx index d156f9d..32aa0ff 100644 --- a/src/components/UsageInstructions.tsx +++ b/src/components/UsageInstructions.tsx @@ -33,12 +33,32 @@ export function UsageInstructions({ config }: UsageInstructionsProps) { }} > {config.enable - ? "LSFG is enabled globally. The layer will be active for all games automatically. No launch arguments needed." - : "LSFG is disabled. Enable it above to activate frame generation for all games." + ? "LSFG is enabled. Add the launch option below to Steam games to activate frame generation." + : "LSFG is disabled. Enable it above and add the launch option to activate frame generation." }
+ +
+ Required Launch Option: +
+ LSFG_PROCESS=decky-lsfg-vk %command% +
+
+
- The configuration is stored in ~/.config/lsfg-vk/conf.toml and applies to all games globally. + Add the launch option to each game's Properties → Launch Options in Steam. The configuration is stored in ~/.config/lsfg-vk/conf.toml and hot-reloads while games are running.
diff --git a/src/components/index.ts b/src/components/index.ts index ec4c194..ed0b803 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -4,5 +4,6 @@ export { InstallationButton } from "./InstallationButton"; export { ConfigurationSection } from "./ConfigurationSection"; // export { UsageInstructions } from "./UsageInstructions"; export { WikiButton } from "./WikiButton"; -// export { ClipboardButton } from "./ClipboardButton"; +export { ClipboardButton } from "./ClipboardButton"; +export { LaunchOptionInfo } from "./LaunchOptionInfo"; export { PluginUpdateChecker } from "./PluginUpdateChecker"; -- cgit v1.2.3 From f3846f88402b6216675c9c48c04ab5a30cce3062 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 12:12:55 -0400 Subject: restore clipboard wiki button --- src/components/ClipboardButton.tsx | 28 +++++----------------------- src/components/ConfigurationSection.tsx | 2 +- src/components/UsageInstructions.tsx | 4 ++-- 3 files changed, 8 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/components/ClipboardButton.tsx b/src/components/ClipboardButton.tsx index cf11e6e..3760e81 100644 --- a/src/components/ClipboardButton.tsx +++ b/src/components/ClipboardButton.tsx @@ -1,26 +1,9 @@ -import { useState } from "react"; import { PanelSectionRow, ButtonItem } from "@decky/ui"; -import { FaClipboard, FaCheck } from "react-icons/fa"; -import { getLaunchOption } from "../api/lsfgApi"; +import { FaExternalLinkAlt } from "react-icons/fa"; export function ClipboardButton() { - const [copied, setCopied] = useState(false); - - const handleClipboardClick = async () => { - try { - // Get the launch option from the backend - const response = await getLaunchOption(); - const launchOption = response.launch_option; - - // Copy to clipboard - await navigator.clipboard.writeText(launchOption); - setCopied(true); - - // Reset the copied state after 2 seconds - setTimeout(() => setCopied(false), 2000); - } catch (error) { - console.error("Failed to copy launch option:", error); - } + const handleClipboardClick = () => { + window.open("https://github.com/xXJSONDeruloXx/decky-lossless-scaling-vk/wiki/Clipboard", "_blank"); }; return ( @@ -28,11 +11,10 @@ export function ClipboardButton() {
- {copied ? : } -
{copied ? "Copied!" : "Copy Launch Option"}
+ +
Launch Option Clipboard
diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index f44dd4f..bfbeb98 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -48,7 +48,7 @@ export function ConfigurationSection({ Required Launch Option:
- LSFG_PROCESS=decky-lsfg-vk %command% + ~/lsfg %command%
@@ -89,7 +89,7 @@ export function UsageInstructions({ config }: UsageInstructionsProps) { marginTop: "8px" }} > - Add the launch option to each game's Properties → Launch Options in Steam. The configuration is stored in ~/.config/lsfg-vk/conf.toml and hot-reloads while games are running. + Add the launch option to each game's Properties → Launch Options in Steam. The lsfg script is automatically created during installation and connects your games to the plugin's configuration. The configuration is stored in ~/.config/lsfg-vk/conf.toml and hot-reloads while games are running. -- cgit v1.2.3 From 420571823c13345112ff608818b47b6b02d23fb4 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 12:24:07 -0400 Subject: feat: hide depreciated enable toggle --- src/components/ConfigurationSection.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index bfbeb98..19c10ea 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -27,14 +27,14 @@ export function ConfigurationSection({ - + {/* onConfigChange('enable', value)} /> - + */} {/* Date: Fri, 18 Jul 2025 12:46:16 -0400 Subject: update descriptions and layouts --- src/components/ConfigurationSection.tsx | 8 ++++---- src/components/UsageInstructions.tsx | 29 ++++++++++++++--------------- 2 files changed, 18 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 19c10ea..8aeded7 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -67,7 +67,7 @@ export function ConfigurationSection({ onConfigChange('performance_mode', value)} /> @@ -118,7 +118,7 @@ export function ConfigurationSection({ selectedOption={config.experimental_present_mode} onChange={(value) => onConfigChange('experimental_present_mode', value.data)} rgOptions={[ - { data: "", label: "Default (FIFO)" }, + { data: "", label: "Default" }, { data: "fifo", label: "FIFO" }, { data: "vsync", label: "VSync" }, { data: "mailbox", label: "Mailbox" }, @@ -130,7 +130,7 @@ export function ConfigurationSection({ 0 ? ` (${config.experimental_fps_limit} FPS)` : ' (Off)'}`} - description="Base framerate cap for DirectX games, before frame multiplier (0 = disabled)" + description="Base framerate cap for DirectX games, before frame multiplier" value={config.experimental_fps_limit} min={0} max={60} diff --git a/src/components/UsageInstructions.tsx b/src/components/UsageInstructions.tsx index fb754b2..8ac94d8 100644 --- a/src/components/UsageInstructions.tsx +++ b/src/components/UsageInstructions.tsx @@ -33,7 +33,7 @@ export function UsageInstructions({ config }: UsageInstructionsProps) { }} > {config.enable - ? "LSFG is enabled. Add the launch option below to Steam games to activate frame generation." + ? "Add the launch option below (or use \"Launch Option Clipboard\") to Steam games to activate frame generation." : "LSFG is disabled. Enable it above and add the launch option to activate frame generation." } @@ -42,24 +42,23 @@ export function UsageInstructions({ config }: UsageInstructionsProps) {
- Required Launch Option: -
~/lsfg %command%
- + {/*
0 ? `${config.experimental_fps_limit} FPS` : "Off"}`}
-
+
*/}
- Add the launch option to each game's Properties → Launch Options in Steam. The lsfg script is automatically created during installation and connects your games to the plugin's configuration. The configuration is stored in ~/.config/lsfg-vk/conf.toml and hot-reloads while games are running. +The configuration is stored in ~/.config/lsfg-vk/conf.toml and hot-reloads while games are running.
-- cgit v1.2.3 From 2bb4544db5a506fbd27e40881f924e839308f6a0 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 13:20:40 -0400 Subject: update descriptions --- src/components/ConfigurationSection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 8aeded7..5767d08 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -113,7 +113,7 @@ export function ConfigurationSection({ onConfigChange('experimental_present_mode', value.data)} @@ -130,7 +130,7 @@ export function ConfigurationSection({ 0 ? ` (${config.experimental_fps_limit} FPS)` : ' (Off)'}`} - description="Base framerate cap for DirectX games, before frame multiplier" + description="Base framerate cap for DirectX games, before frame multiplier (requires game re-launch)" value={config.experimental_fps_limit} min={0} max={60} -- cgit v1.2.3 From bb76e4e61a608b9ce77de6f2e2bce2ce1f3839ea Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Fri, 18 Jul 2025 15:09:32 -0400 Subject: update descriptions --- src/components/ConfigurationSection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 5767d08..dc8da89 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -48,7 +48,7 @@ export function ConfigurationSection({