From c3f510a2944cf8436c8bccedcb77db9bd6a7f2c3 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 12:50:03 -0400 Subject: chore: remove unused elements previously commented out, for store release prep --- README.md | 10 +- assets/logo.png | Bin 21108 -> 0 bytes assets/qam-screenshot.jpeg | Bin 60314 -> 0 bytes decky.pyi | 184 --------------------------------- defaults/defaults.txt | 13 --- src/api/lsfgApi.ts | 20 ---- src/components/ClipboardButton.tsx | 22 ---- src/components/ClipboardDisplay.tsx | 139 ------------------------- src/components/Content.tsx | 16 +-- src/components/PluginUpdateChecker.tsx | 176 ------------------------------- src/components/WikiButton.tsx | 22 ---- src/components/index.ts | 11 ++ 12 files changed, 17 insertions(+), 596 deletions(-) delete mode 100644 assets/logo.png delete mode 100644 assets/qam-screenshot.jpeg delete mode 100644 decky.pyi delete mode 100644 defaults/defaults.txt delete mode 100644 src/components/ClipboardButton.tsx delete mode 100644 src/components/ClipboardDisplay.tsx delete mode 100644 src/components/PluginUpdateChecker.tsx delete mode 100644 src/components/WikiButton.tsx create mode 100644 src/components/index.ts diff --git a/README.md b/README.md index 609f77c..de75050 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ > **Note:** > This is an **unofficial community plugin**. It is independently developed and **not officially supported** by the creators of Lossless Scaling or lsfg-vk. For support, please use the [decky-lsfg-vk Discord Channel](https://discord.gg/TwvHdVucC3). + +

+ decky-lsfg-vk Logo +

Support on Ko-fi @@ -10,12 +14,6 @@

- -

- decky-lsfg-vk Logo -

- - ## What is this? A Decky plugin that streamlines the installation of **lsfg-vk** ([Lossless Scaling Frame Generation Vulkan layer](https://github.com/PancakeTAS/lsfg-vk)) on Steam Deck, allowing you to use the Lossless Scaling frame generation features on Linux with a controller friendly UI in SteamOS, Bazzite, or any other Linux platform compatible with Decky Loader. diff --git a/assets/logo.png b/assets/logo.png deleted file mode 100644 index 48c4851..0000000 Binary files a/assets/logo.png and /dev/null differ diff --git a/assets/qam-screenshot.jpeg b/assets/qam-screenshot.jpeg deleted file mode 100644 index 8df12b2..0000000 Binary files a/assets/qam-screenshot.jpeg and /dev/null differ diff --git a/decky.pyi b/decky.pyi deleted file mode 100644 index a72c74c..0000000 --- a/decky.pyi +++ /dev/null @@ -1,184 +0,0 @@ -""" -This module exposes various constants and helpers useful for decky plugins. - -* Plugin's settings and configurations should be stored under `DECKY_PLUGIN_SETTINGS_DIR`. -* Plugin's runtime data should be stored under `DECKY_PLUGIN_RUNTIME_DIR`. -* Plugin's persistent log files should be stored under `DECKY_PLUGIN_LOG_DIR`. - -Avoid writing outside of `DECKY_HOME`, storing under the suggested paths is strongly recommended. - -Some basic migration helpers are available: `migrate_any`, `migrate_settings`, `migrate_runtime`, `migrate_logs`. - -A logging facility `logger` is available which writes to the recommended location. -""" - -__version__ = '1.0.0' - -import logging - -from typing import Any - -""" -Constants -""" - -HOME: str -""" -The home directory of the effective user running the process. -Environment variable: `HOME`. -If `root` was specified in the plugin's flags it will be `/root` otherwise the user whose home decky resides in. -e.g.: `/home/deck` -""" - -USER: str -""" -The effective username running the process. -Environment variable: `USER`. -It would be `root` if `root` was specified in the plugin's flags otherwise the user whose home decky resides in. -e.g.: `deck` -""" - -DECKY_VERSION: str -""" -The version of the decky loader. -Environment variable: `DECKY_VERSION`. -e.g.: `v2.5.0-pre1` -""" - -DECKY_USER: str -""" -The user whose home decky resides in. -Environment variable: `DECKY_USER`. -e.g.: `deck` -""" - -DECKY_USER_HOME: str -""" -The home of the user where decky resides in. -Environment variable: `DECKY_USER_HOME`. -e.g.: `/home/deck` -""" - -DECKY_HOME: str -""" -The root of the decky folder. -Environment variable: `DECKY_HOME`. -e.g.: `/home/deck/homebrew` -""" - -DECKY_PLUGIN_SETTINGS_DIR: str -""" -The recommended path in which to store configuration files (created automatically). -Environment variable: `DECKY_PLUGIN_SETTINGS_DIR`. -e.g.: `/home/deck/homebrew/settings/decky-plugin-template` -""" - -DECKY_PLUGIN_RUNTIME_DIR: str -""" -The recommended path in which to store runtime data (created automatically). -Environment variable: `DECKY_PLUGIN_RUNTIME_DIR`. -e.g.: `/home/deck/homebrew/data/decky-plugin-template` -""" - -DECKY_PLUGIN_LOG_DIR: str -""" -The recommended path in which to store persistent logs (created automatically). -Environment variable: `DECKY_PLUGIN_LOG_DIR`. -e.g.: `/home/deck/homebrew/logs/decky-plugin-template` -""" - -DECKY_PLUGIN_DIR: str -""" -The root of the plugin's directory. -Environment variable: `DECKY_PLUGIN_DIR`. -e.g.: `/home/deck/homebrew/plugins/decky-plugin-template` -""" - -DECKY_PLUGIN_NAME: str -""" -The name of the plugin as specified in the 'plugin.json'. -Environment variable: `DECKY_PLUGIN_NAME`. -e.g.: `Example Plugin` -""" - -DECKY_PLUGIN_VERSION: str -""" -The version of the plugin as specified in the 'package.json'. -Environment variable: `DECKY_PLUGIN_VERSION`. -e.g.: `0.0.1` -""" - -DECKY_PLUGIN_AUTHOR: str -""" -The author of the plugin as specified in the 'plugin.json'. -Environment variable: `DECKY_PLUGIN_AUTHOR`. -e.g.: `John Doe` -""" - -DECKY_PLUGIN_LOG: str -""" -The path to the plugin's main logfile. -Environment variable: `DECKY_PLUGIN_LOG`. -e.g.: `/home/deck/homebrew/logs/decky-plugin-template/plugin.log` -""" - -""" -Migration helpers -""" - - -def migrate_any(target_dir: str, *files_or_directories: str) -> dict[str, str]: - """ - Migrate files and directories to a new location and remove old locations. - Specified files will be migrated to `target_dir`. - Specified directories will have their contents recursively migrated to `target_dir`. - - Returns the mapping of old -> new location. - """ - - -def migrate_settings(*files_or_directories: str) -> dict[str, str]: - """ - Migrate files and directories relating to plugin settings to the recommended location and remove old locations. - Specified files will be migrated to `DECKY_PLUGIN_SETTINGS_DIR`. - Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_SETTINGS_DIR`. - - Returns the mapping of old -> new location. - """ - - -def migrate_runtime(*files_or_directories: str) -> dict[str, str]: - """ - Migrate files and directories relating to plugin runtime data to the recommended location and remove old locations - Specified files will be migrated to `DECKY_PLUGIN_RUNTIME_DIR`. - Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_RUNTIME_DIR`. - - Returns the mapping of old -> new location. - """ - - -def migrate_logs(*files_or_directories: str) -> dict[str, str]: - """ - Migrate files and directories relating to plugin logs to the recommended location and remove old locations. - Specified files will be migrated to `DECKY_PLUGIN_LOG_DIR`. - Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_LOG_DIR`. - - Returns the mapping of old -> new location. - """ - - -""" -Logging -""" - -logger: logging.Logger -"""The main plugin logger writing to `DECKY_PLUGIN_LOG`.""" - -""" -Event handling -""" -# TODO better docstring im lazy -async def emit(event: str, *args: Any) -> None: - """ - Send an event to the frontend. - """ \ No newline at end of file diff --git a/defaults/defaults.txt b/defaults/defaults.txt deleted file mode 100644 index ebf140b..0000000 --- a/defaults/defaults.txt +++ /dev/null @@ -1,13 +0,0 @@ -If you have plain-text json configs, theme templates, or templates for usage for your plugin of any description you should have those files be in here. -Those files will be pulled into the zip during the build process and included with the upload. Example: CssLoader with it's themes in "default/themes" would have the "themes" folder will be added alongside with the dist folder, main.py, LICENSE and README files in the subfolder of the zip containing the plugin. -Files can also be put in here such as a config, just keep in mind that they this directory cannot be utilized to put files in arbitrary locations, just within the extracted root folder of the plugin, ex: CssLoader has "defaults/themes/..." setup in it's repo, but when packaged to go to the store, the file structure will be: - -- LICENSE -- README -- dist - - index.js -- main.py -- package.json -- plugin.json -- themes - - exampletheme.css \ No newline at end of file diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index dda6c23..82f37c8 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -59,23 +59,6 @@ export interface ConfigSchemaResult { current_profile?: string; } -export interface UpdateCheckResult { - success: boolean; - update_available: boolean; - current_version: string; - latest_version: string; - release_notes: string; - release_date: string; - download_url: string; - error?: string; -} - -export interface UpdateDownloadResult { - success: boolean; - download_path?: string; - error?: string; -} - export interface LaunchOptionResult { launch_option: string; instructions: string; @@ -178,9 +161,6 @@ export const updateLsfgConfigFromObject = async (config: ConfigurationData): Pro }; // Self-updater API functions -export const checkForPluginUpdate = callable<[], UpdateCheckResult>("check_for_plugin_update"); -export const downloadPluginUpdate = callable<[string], UpdateDownloadResult>("download_plugin_update"); - // Profile management API functions export const getProfiles = callable<[], ProfilesResult>("get_profiles"); export const createProfile = callable<[string, string?], ProfileResult>("create_profile"); diff --git a/src/components/ClipboardButton.tsx b/src/components/ClipboardButton.tsx deleted file mode 100644 index cac1863..0000000 --- a/src/components/ClipboardButton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { PanelSectionRow, ButtonItem } from "@decky/ui"; -import { FaBook } from "react-icons/fa"; - -export function ClipboardButton() { - const handleClipboardClick = () => { - window.open("https://github.com/xXJSONDeruloXx/decky-lossless-scaling-vk/wiki/Clipboard", "_blank"); - }; - - return ( - - -
- -
Plugin Wiki
-
-
-
- ); -} diff --git a/src/components/ClipboardDisplay.tsx b/src/components/ClipboardDisplay.tsx deleted file mode 100644 index 852a50f..0000000 --- a/src/components/ClipboardDisplay.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { useState, useEffect } from "react"; -import { PanelSectionRow } from "@decky/ui"; -import { FaClipboard, FaEye } from "react-icons/fa"; - -export function ClipboardDisplay() { - const [clipboardContent, setClipboardContent] = useState(""); - const [isReading, setIsReading] = useState(false); - - const readClipboard = async () => { - if (isReading) return; // Prevent concurrent reads - - setIsReading(true); - try { - console.log("ClipboardDisplay: Attempting to read clipboard..."); - - if (!navigator.clipboard) { - console.log("ClipboardDisplay: navigator.clipboard not available"); - setClipboardContent("Clipboard API not available"); - return; - } - - if (!navigator.clipboard.readText) { - console.log("ClipboardDisplay: navigator.clipboard.readText not available"); - setClipboardContent("Clipboard read not supported"); - return; - } - - console.log("ClipboardDisplay: Calling navigator.clipboard.readText()..."); - const content = await navigator.clipboard.readText(); - console.log("ClipboardDisplay: Successfully read clipboard:", content.length, "characters"); - setClipboardContent(content); - } catch (error) { - // This is expected if user hasn't granted clipboard permissions - // or if we're in a context where reading isn't allowed - console.log("ClipboardDisplay: Error reading clipboard:", error); - console.log("ClipboardDisplay: Error name:", (error as Error).name); - console.log("ClipboardDisplay: Error message:", (error as Error).message); - - // More specific error messages based on error type - if (error instanceof DOMException) { - switch (error.name) { - case 'NotAllowedError': - setClipboardContent("Clipboard access denied - check permissions"); - break; - case 'NotFoundError': - setClipboardContent("No clipboard data found"); - break; - case 'SecurityError': - setClipboardContent("Clipboard access blocked by security policy"); - break; - default: - setClipboardContent(`Clipboard error: ${error.name}`); - } - } else { - setClipboardContent("Unable to read clipboard"); - } - } finally { - setIsReading(false); - } - }; - - // Read clipboard on mount and then every 3 seconds - useEffect(() => { - readClipboard(); - - const interval = setInterval(() => { - readClipboard(); - }, 3000); - - return () => clearInterval(interval); - }, []); - - const truncateText = (text: string, maxLength: number = 60) => { - if (text.length <= maxLength) return text; - return text.substring(0, maxLength) + "..."; - }; - - const displayText = truncateText(clipboardContent); - - return ( - -
-
- -
- Current Clipboard -
- {isReading && ( - - )} -
-
- {displayText || "Reading clipboard..."} -
-
- -
- ); -} diff --git a/src/components/Content.tsx b/src/components/Content.tsx index fdb8672..08027d3 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -8,12 +8,8 @@ import { InstallationButton } from "./InstallationButton"; import { ConfigurationSection } from "./ConfigurationSection"; import { ProfileManagement } from "./ProfileManagement"; import { UsageInstructions } from "./UsageInstructions"; -// import { WikiButton } from "./WikiButton"; -// import { ClipboardButton } from "./ClipboardButton"; import { SmartClipboardButton } from "./SmartClipboardButton"; import { FgmodClipboardButton } from "./FgmodClipboardButton"; -// import { ClipboardDisplay } from "./ClipboardDisplay"; -// import { PluginUpdateChecker } from "./PluginUpdateChecker"; import { NerdStuffModal } from "./NerdStuffModal"; import FlatpaksModal from "./FlatpaksModal"; import { ConfigurationData } from "../config/configSchema"; @@ -106,7 +102,6 @@ export function Content() { {/* Clipboard buttons - only show if installed */} {isInstalled && ( <> - {/* */} @@ -131,15 +126,8 @@ export function Content() { /> )} - {/* Usage instructions - always visible for user guidance */} - - - {/* Wiki and clipboard buttons - always available for documentation */} - {/* */} - {/* */} - - {/* Plugin Update Checker */} - {/* */} + {/* Usage instructions - always visible for user guidance */} + {/* Show installation components at bottom when fully installed */} {isInstalled && ( diff --git a/src/components/PluginUpdateChecker.tsx b/src/components/PluginUpdateChecker.tsx deleted file mode 100644 index 9fa2afb..0000000 --- a/src/components/PluginUpdateChecker.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { - ButtonItem, - PanelSection, - PanelSectionRow, - Field, - Focusable -} from '@decky/ui'; -import { checkForPluginUpdate, downloadPluginUpdate, UpdateCheckResult, UpdateDownloadResult } from '../api/lsfgApi'; - -interface PluginUpdateCheckerProps { - // Add any props if needed -} - -interface UpdateInfo { - updateAvailable: boolean; - currentVersion: string; - latestVersion: string; - releaseNotes: string; - releaseDate: string; - downloadUrl: string; -} - -export const PluginUpdateChecker: React.FC = () => { - const [checkingUpdate, setCheckingUpdate] = useState(false); - const [downloadingUpdate, setDownloadingUpdate] = useState(false); - const [updateInfo, setUpdateInfo] = useState(null); - const [updateError, setUpdateError] = useState(null); - const [downloadResult, setDownloadResult] = useState(null); - - // Auto-hide error messages after 5 seconds - useEffect(() => { - if (updateError) { - const timer = setTimeout(() => { - setUpdateError(null); - }, 5000); - return () => clearTimeout(timer); - } - return undefined; - }, [updateError]); - - const handleCheckForUpdate = async () => { - setCheckingUpdate(true); - setUpdateError(null); - setUpdateInfo(null); - setDownloadResult(null); // Clear previous download result - - try { - const result: UpdateCheckResult = await checkForPluginUpdate(); - - if (result.success) { - setUpdateInfo({ - updateAvailable: result.update_available, - currentVersion: result.current_version, - latestVersion: result.latest_version, - releaseNotes: result.release_notes, - releaseDate: result.release_date, - downloadUrl: result.download_url - }); - - // Simple console log instead of toast since showToast may not be available - if (result.update_available) { - console.log("Update available!", `Version ${result.latest_version} is now available.`); - } else { - console.log("Up to date!", "You have the latest version installed."); - } - } else { - setUpdateError(result.error || "Failed to check for updates"); - } - } catch (error) { - setUpdateError(`Error checking for updates: ${error}`); - } finally { - setCheckingUpdate(false); - } - }; - - const handleDownloadUpdate = async () => { - if (!updateInfo?.downloadUrl) return; - - setDownloadingUpdate(true); - setUpdateError(null); - setDownloadResult(null); - - try { - const result: UpdateDownloadResult = await downloadPluginUpdate(updateInfo.downloadUrl); - - if (result.success) { - setDownloadResult(result); - console.log("✓ Download complete!", `Plugin downloaded to ${result.download_path}`); - } else { - setUpdateError(result.error || "Failed to download update"); - } - } catch (error) { - setUpdateError(`Error downloading update: ${error}`); - } finally { - setDownloadingUpdate(false); - } - }; - - const getStatusMessage = () => { - if (!updateInfo) return null; - - if (updateInfo.updateAvailable) { - if (downloadResult?.success) { - return "✓ v" + updateInfo.latestVersion + " downloaded - ready to install"; - } else { - return "Update available: v" + updateInfo.latestVersion; - } - } else { - return "Up to date (v" + updateInfo.currentVersion + ")"; - } - }; - - return ( - - - - {checkingUpdate ? 'Checking for updates...' : 'Check for Updates'} - - - - {updateInfo && updateInfo.updateAvailable && !downloadResult?.success && ( - - - {downloadingUpdate ? 'Downloading...' : 'Download Update'} - - - )} - - {downloadResult?.success && ( - <> - - - - File saved to: {downloadResult.download_path} - - - - - - - - 1. Go to Decky Loader settings -
2. Click "Developer" tab -
3. Click "Uninstall" next to "decky-lsfg-vk" -
4. Click "Install from ZIP" -
5. Select the downloaded file -
6. Restart Steam or reload plugins -
-
-
- - )} - - {updateError && ( - - - - {updateError} - - - - )} -
- ); -}; diff --git a/src/components/WikiButton.tsx b/src/components/WikiButton.tsx deleted file mode 100644 index 065fb8e..0000000 --- a/src/components/WikiButton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { PanelSectionRow, ButtonItem } from "@decky/ui"; -import { FaBook } from "react-icons/fa"; - -export function WikiButton() { - const handleWikiClick = () => { - window.open("https://github.com/PancakeTAS/lsfg-vk/wiki", "_blank"); - }; - - return ( - - -
- -
LSFG-VK Wiki
-
-
-
- ); -} diff --git a/src/components/index.ts b/src/components/index.ts new file mode 100644 index 0000000..95e7451 --- /dev/null +++ b/src/components/index.ts @@ -0,0 +1,11 @@ +export { Content } from "./Content"; +export { StatusDisplay } from "./StatusDisplay"; +export { InstallationButton } from "./InstallationButton"; +export { ConfigurationSection } from "./ConfigurationSection"; +export { FpsMultiplierControl } from "./FpsMultiplierControl"; +export { UsageInstructions } from "./UsageInstructions"; +export { SmartClipboardButton } from "./SmartClipboardButton"; +export { FgmodClipboardButton } from "./FgmodClipboardButton"; +export { NerdStuffModal } from "./NerdStuffModal"; +export { default as FlatpaksModal } from "./FlatpaksModal"; +export { ProfileManagement } from "./ProfileManagement"; -- cgit v1.2.3 From 6c1197ce3b696c1744abcac7ad13d855b80389cd Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 12:52:17 -0400 Subject: chore: rm template flags --- package.json | 2 +- plugin.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ee49d1d..2ca9dd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decky-lsfg-vk", - "version": "0.11.3", + "version": "0.11.4", "description": "Use Lossless Scaling on the Steam Deck using the lsfg-vk vulkan layer", "type": "module", "scripts": { diff --git a/plugin.json b/plugin.json index 67bc281..acd05ef 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "name": "Decky LSFG-VK", "author": "Kurt Himebauch", - "flags": ["debug", "_root"], + "flags": [], "api_version": 1, "publish": { "tags": ["installer", "vulkan", "lsfg"], -- cgit v1.2.3 From 13495d4a6c7448ee8ff6b3e64d423a53ce93bee9 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 12:55:00 -0400 Subject: chore: update tags --- plugin.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.json b/plugin.json index acd05ef..009c589 100644 --- a/plugin.json +++ b/plugin.json @@ -4,8 +4,8 @@ "flags": [], "api_version": 1, "publish": { - "tags": ["installer", "vulkan", "lsfg"], - "description": "Enable frame generation on the Steam Deck using lsfg-vk compatibility layer.", + "tags": ["installer", "vulkan", "lsfg", "framegen", "lossless", "scaling"], + "description": "Enable lossless scaling frame generation on the Steam Deck using lsfg-vk compatibility layer.", "image": "https://steamcommunity.com/sharedfiles/filedetails/?id=3522791434" } } -- cgit v1.2.3 From 194eb12b3efc65ee48449bade8df9872a99b1215 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 13:05:47 -0400 Subject: chore: make barrel imports and refs consistent --- src/components/Content.tsx | 4 ++-- src/components/FlatpaksModal.tsx | 4 +--- src/components/index.ts | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/Content.tsx b/src/components/Content.tsx index 08027d3..8fb3fe3 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -11,7 +11,7 @@ import { UsageInstructions } from "./UsageInstructions"; import { SmartClipboardButton } from "./SmartClipboardButton"; import { FgmodClipboardButton } from "./FgmodClipboardButton"; import { NerdStuffModal } from "./NerdStuffModal"; -import FlatpaksModal from "./FlatpaksModal"; +import { FlatpaksModal } from "./FlatpaksModal"; import { ConfigurationData } from "../config/configSchema"; export function Content() { @@ -165,7 +165,7 @@ export function Content() { layout="below" onClick={handleShowFlatpaks} > - Flatpaks + Flatpak Setup diff --git a/src/components/FlatpaksModal.tsx b/src/components/FlatpaksModal.tsx index ae0c333..ca15a25 100644 --- a/src/components/FlatpaksModal.tsx +++ b/src/components/FlatpaksModal.tsx @@ -32,7 +32,7 @@ interface FlatpaksModalProps { closeModal?: () => void; } -const FlatpaksModal: FC = ({ closeModal }) => { +export const FlatpaksModal: FC = ({ closeModal }) => { const [extensionStatus, setExtensionStatus] = useState(null); const [flatpakApps, setFlatpakApps] = useState(null); const [loading, setLoading] = useState(true); @@ -419,5 +419,3 @@ const FlatpaksModal: FC = ({ closeModal }) => { ); }; - -export default FlatpaksModal; diff --git a/src/components/index.ts b/src/components/index.ts index 95e7451..bec45ae 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -7,5 +7,5 @@ export { UsageInstructions } from "./UsageInstructions"; export { SmartClipboardButton } from "./SmartClipboardButton"; export { FgmodClipboardButton } from "./FgmodClipboardButton"; export { NerdStuffModal } from "./NerdStuffModal"; -export { default as FlatpaksModal } from "./FlatpaksModal"; +export { FlatpaksModal } from "./FlatpaksModal"; export { ProfileManagement } from "./ProfileManagement"; -- cgit v1.2.3 From 299eab282315e7b2c05c5af0cf9eb9d7171e69ca Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 13:24:15 -0400 Subject: fix: make each flatpak step focusable for controller scroll --- src/components/FlatpaksModal.tsx | 147 +++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 68 deletions(-) diff --git a/src/components/FlatpaksModal.tsx b/src/components/FlatpaksModal.tsx index ca15a25..ca69ec6 100644 --- a/src/components/FlatpaksModal.tsx +++ b/src/components/FlatpaksModal.tsx @@ -1,4 +1,4 @@ -import { FC, useState, useEffect } from 'react'; +import { FC, useState, useEffect, CSSProperties } from 'react'; import { ModalRoot, DialogBody, @@ -126,6 +126,40 @@ export const FlatpaksModal: FC = ({ closeModal }) => { ); } + const instructionSteps = [ + { + id: 'try-first', + title: 'Try first:', + command: '~/lsfg' + }, + { + id: 'try-full-path', + title: "If that doesn't work, try full path:", + command: '/home/(username)/lsfg' + }, + { + id: 'final-result', + title: 'Final result should look like:', + command: '~/lsfg "usr/bin/flatpak"' + } + ]; + + const focusableInstructionStyle: CSSProperties = { + padding: '10px', + background: 'rgba(0, 0, 0, 0.3)', + borderRadius: '6px', + marginBottom: '12px' + }; + + const commandStyle: CSSProperties = { + fontFamily: 'monospace', + fontSize: '0.85em', + background: 'rgba(0, 0, 0, 0.45)', + padding: '8px', + borderRadius: '4px', + marginTop: '6px' + }; + return ( Flatpak Extensions @@ -327,80 +361,57 @@ export const FlatpaksModal: FC = ({ closeModal }) => { {/* Steam Configuration Instructions */} Steam Configuration - - -
-
- Configure Steam Flatpak Shortcuts -
-
- In Steam, open your flatpak game and click the cog wheel." -
-
- IMPORTANT: Set this in TARGET (NOT LAUNCH OPTIONS) -
- -
- Try first: -
-
- ~/lsfg -
- -
- If that doesn't work, try full path: -
-
- /home/(username)/lsfg -
- -
- Final result should look like: -
-
- ~/lsfg "usr/bin/flatpak" -
- - {/* Visual example image */} -
- +
+ Configure Steam Flatpak Shortcuts +
+
+ In Steam, open your flatpak game and click the cog wheel. +
+
+ IMPORTANT: Set this in TARGET (NOT LAUNCH OPTIONS) +
+ + {instructionSteps.map((step) => ( + {}} + style={focusableInstructionStyle} + > +
{step.title}
+
{step.command}
+
+ ))} + + {}} + style={{ marginTop: '4px' }} + > +
+ Steam Properties Target Field Example
-
- + +
{/* Close Button */} -- cgit v1.2.3 From 23923d16565d7007f438599bca8b45c44358b11a Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 13:27:31 -0400 Subject: chore: bump ver --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ca9dd7..6642119 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decky-lsfg-vk", - "version": "0.11.4", + "version": "0.11.5", "description": "Use Lossless Scaling on the Steam Deck using the lsfg-vk vulkan layer", "type": "module", "scripts": { -- cgit v1.2.3 From c07cf0dde2f26ec3ac672efe06da7cd991ed208b Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 13:40:18 -0400 Subject: chore: move uninstall and statuses locations in ui --- src/components/Content.tsx | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/components/Content.tsx b/src/components/Content.tsx index 8fb3fe3..71329ad 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -126,28 +126,8 @@ export function Content() { /> )} - {/* Usage instructions - always visible for user guidance */} - - - {/* Show installation components at bottom when fully installed */} - {isInstalled && ( - <> - - - - - )} + {/* Usage instructions - always visible for user guidance */} + {/* Nerd Stuff Button */} @@ -168,6 +148,26 @@ export function Content() { Flatpak Setup + + {/* Status and uninstall sit at bottom when installed to match desired layout */} + {isInstalled && ( + <> + + + + + )} ); } -- cgit v1.2.3 From 45768e35b7e579bc795f33e802287bdf25c191cb Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 13:41:42 -0400 Subject: chore: rename dll to more clearly ref lossless dll --- src/components/NerdStuffModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/NerdStuffModal.tsx b/src/components/NerdStuffModal.tsx index b5689c9..89a6547 100644 --- a/src/components/NerdStuffModal.tsx +++ b/src/components/NerdStuffModal.tsx @@ -86,7 +86,7 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { - + dllStats.dll_sha256 && copyToClipboard(dllStats.dll_sha256)} onActivate={() => dllStats.dll_sha256 && copyToClipboard(dllStats.dll_sha256)} -- cgit v1.2.3 From 6c1b16cc4ecd1dc6c28882374419653538dca8f9 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 13:53:36 -0400 Subject: feat: collapsible config section above workarounds --- src/components/ConfigurationSection.tsx | 154 ++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 47 deletions(-) diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index b098b32..632c3a0 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -14,13 +14,23 @@ interface ConfigurationSectionProps { onConfigChange: (fieldName: keyof ConfigurationData, value: boolean | number | string) => Promise; } -const WORKAROUNDS_COLLAPSED_KEY = 'lsfg-workarounds-collapsed'; +const WORKAROUNDS_COLLAPSED_KEY = "lsfg-workarounds-collapsed"; +const CONFIG_COLLAPSED_KEY = "lsfg-config-collapsed"; export function ConfigurationSection({ config, onConfigChange }: ConfigurationSectionProps) { // Initialize with localStorage value, fallback to true if not found + const [configCollapsed, setConfigCollapsed] = useState(() => { + try { + const saved = localStorage.getItem(CONFIG_COLLAPSED_KEY); + return saved !== null ? JSON.parse(saved) : false; + } catch { + return false; + } + }); + const [workaroundsCollapsed, setWorkaroundsCollapsed] = useState(() => { try { const saved = localStorage.getItem(WORKAROUNDS_COLLAPSED_KEY); @@ -31,11 +41,19 @@ export function ConfigurationSection({ }); // Persist workarounds collapse state to localStorage + useEffect(() => { + try { + localStorage.setItem(CONFIG_COLLAPSED_KEY, JSON.stringify(configCollapsed)); + } catch (error) { + console.warn("Failed to save config collapse state:", error); + } + }, [configCollapsed]); + useEffect(() => { try { localStorage.setItem(WORKAROUNDS_COLLAPSED_KEY, JSON.stringify(workaroundsCollapsed)); } catch (error) { - console.warn('Failed to save workarounds collapse state:', error); + console.warn("Failed to save workarounds collapse state:", error); } }, [workaroundsCollapsed]); @@ -43,6 +61,8 @@ export function ConfigurationSection({ <> - {/* FPS Multiplier */} - - + {/* Config Section */} - onConfigChange(FLOW_SCALE, value)} - /> +
+ Config +
- 0 ? ` (${config.dxvk_frame_rate} FPS)` : ' (Off)'}`} - description="Base framerate cap for DirectX games, before frame multiplier. (Requires game restart to apply)" - value={config.dxvk_frame_rate} - min={0} - max={60} - step={1} - onChange={(value) => onConfigChange(DXVK_FRAME_RATE, value)} - /> +
+ setConfigCollapsed(!configCollapsed)} + > + {configCollapsed ? ( + + ) : ( + + )} + +
- - onConfigChange(EXPERIMENTAL_PRESENT_MODE, value ? "fifo" : "mailbox")} - /> - + {!configCollapsed && ( + <> + - - onConfigChange(PERFORMANCE_MODE, value)} - /> - + + onConfigChange(FLOW_SCALE, value)} + /> + - - onConfigChange(HDR_MODE, value)} - /> - + + 0 ? ` (${config.dxvk_frame_rate} FPS)` : " (Off)"}`} + description="Base framerate cap for DirectX games, before frame multiplier. (Requires game restart to apply)" + value={config.dxvk_frame_rate} + min={0} + max={60} + step={1} + onChange={(value) => onConfigChange(DXVK_FRAME_RATE, value)} + /> + + + + onConfigChange(EXPERIMENTAL_PRESENT_MODE, value ? "fifo" : "mailbox")} + /> + + + + onConfigChange(PERFORMANCE_MODE, value)} + /> + + + + onConfigChange(HDR_MODE, value)} + /> + + + )} {/* Workarounds Section */} -- cgit v1.2.3 From f2a2f4a126c5b60a2f8115c850883ccb8d736825 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 14:20:32 -0400 Subject: chore: move fps mul to top --- src/components/ConfigurationSection.tsx | 3 --- src/components/Content.tsx | 21 +++++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 632c3a0..eeacf05 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -2,7 +2,6 @@ import { PanelSectionRow, ToggleField, SliderField, ButtonItem } from "@decky/ui import { useState, useEffect } from "react"; import { RiArrowDownSFill, RiArrowUpSFill } from "react-icons/ri"; import { ConfigurationData } from "../config/configSchema"; -import { FpsMultiplierControl } from "./FpsMultiplierControl"; import { FLOW_SCALE, PERFORMANCE_MODE, HDR_MODE, EXPERIMENTAL_PRESENT_MODE, DXVK_FRAME_RATE, DISABLE_STEAMDECK_MODE, @@ -111,8 +110,6 @@ export function ConfigurationSection({ {!configCollapsed && ( <> - - )} - - {/* Clipboard buttons - only show if installed */} + + {/* FPS multiplier controls stay above profile selection when installed */} {isInstalled && ( - <> - - - + )} {/* Profile Management - only show if installed */} @@ -126,6 +127,14 @@ export function Content() { /> )} + {/* Clipboard buttons sit beside usage info for quick access */} + {isInstalled && ( + <> + + + + )} + {/* Usage instructions - always visible for user guidance */} -- cgit v1.2.3 From 8dcfea10e22d783a8adc6b1564e10bd32777a665 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 14:26:05 -0400 Subject: chore: compact spacing for collapsibles --- src/components/ConfigurationSection.tsx | 22 ++++++++++++++-------- src/components/FpsMultiplierControl.tsx | 4 ++-- src/components/ProfileManagement.tsx | 11 +++++++---- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index eeacf05..0734297 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -77,10 +77,10 @@ export function ConfigurationSection({ style={{ fontSize: "14px", fontWeight: "bold", - marginTop: "16px", - marginBottom: "8px", + marginTop: "8px", + marginBottom: "6px", borderBottom: "1px solid rgba(255, 255, 255, 0.2)", - paddingBottom: "4px", + paddingBottom: "3px", color: "white" }} > @@ -89,7 +89,10 @@ export function ConfigurationSection({ -
+
@@ -181,7 +184,10 @@ export function ConfigurationSection({ -
+
@@ -379,7 +379,10 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa -
+
Date: Mon, 20 Oct 2025 14:44:37 -0400 Subject: add consistent headders and bump ver, recipe for tmp storage purge --- justfile | 3 ++- package.json | 2 +- src/components/Content.tsx | 26 ++++++++++++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/justfile b/justfile index abd24c2..54148ad 100644 --- a/justfile +++ b/justfile @@ -17,4 +17,5 @@ cef: tail -f ~/.local/share/Steam/logs/cef_log.txt clean: - rm -rf node_modules dist \ No newline at end of file + rm -rf node_modules dist + sudo rm -rf /tmp/decky \ No newline at end of file diff --git a/package.json b/package.json index 6642119..dc45048 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decky-lsfg-vk", - "version": "0.11.5", + "version": "0.12.0", "description": "Use Lossless Scaling on the Steam Deck using the lsfg-vk vulkan layer", "type": "module", "scripts": { diff --git a/src/components/Content.tsx b/src/components/Content.tsx index 24dcb5f..28eefa7 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -102,10 +102,28 @@ export function Content() { {/* FPS multiplier controls stay above profile selection when installed */} {isInstalled && ( - + <> + +
+ FPS Multiplier +
+
+ + + )} {/* Profile Management - only show if installed */} -- cgit v1.2.3 From 2fcac839c23df7dfdfe0634189eaeb1e8e5824a1 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 15:01:10 -0400 Subject: chore: align close button implementation in nerd stuff w flatpak modal --- src/components/NerdStuffModal.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/components/NerdStuffModal.tsx b/src/components/NerdStuffModal.tsx index 89a6547..b4a79a2 100644 --- a/src/components/NerdStuffModal.tsx +++ b/src/components/NerdStuffModal.tsx @@ -3,7 +3,9 @@ import { ModalRoot, Field, Focusable, - Button + DialogControlsSection, + PanelSectionRow, + ButtonItem } from "@decky/ui"; import { getDllStats, DllStatsResult, getConfigFileContent, getLaunchScriptContent, FileContentResult } from "../api/lsfgApi"; @@ -166,9 +168,17 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { )} - + {/* Close Button */} + + + + Close + + + )} -- cgit v1.2.3 From ec37b86c5d4a6371804e71e7863df6a71c756db3 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Mon, 20 Oct 2025 15:19:42 -0400 Subject: feat: add DXVK_HDR=0 when enable wsi toggled off --- py_modules/lsfg_vk/config_schema_generated.py | 3 +++ scripts/generate_python_boilerplate.py | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/py_modules/lsfg_vk/config_schema_generated.py b/py_modules/lsfg_vk/config_schema_generated.py index 6a0a7f6..53e9693 100644 --- a/py_modules/lsfg_vk/config_schema_generated.py +++ b/py_modules/lsfg_vk/config_schema_generated.py @@ -81,6 +81,8 @@ def get_script_parsing_logic(): script_values["force_enable_vkbasalt"] = value == "1" if key == "ENABLE_GAMESCOPE_WSI": script_values["enable_wsi"] = value != "0" + if key == "DXVK_HDR": + script_values["enable_wsi"] = value != "0" if key == "__GLX_VENDOR_LIBRARY_NAME" and value == "mesa": script_values["enable_zink"] = True if key == "MESA_LOADER_DRIVER_OVERRIDE" and value == "zink": @@ -111,6 +113,7 @@ def get_script_generation_logic(): lines.append("export ENABLE_VKBASALT=1") if not config.get("enable_wsi", False): lines.append("export ENABLE_GAMESCOPE_WSI=0") + lines.append("export DXVK_HDR=0") if config.get("enable_zink", False): lines.append("export __GLX_VENDOR_LIBRARY_NAME=mesa") lines.append("export MESA_LOADER_DRIVER_OVERRIDE=zink") diff --git a/scripts/generate_python_boilerplate.py b/scripts/generate_python_boilerplate.py index 26bcfa5..dc51dae 100644 --- a/scripts/generate_python_boilerplate.py +++ b/scripts/generate_python_boilerplate.py @@ -108,9 +108,11 @@ def generate_script_parsing() -> str: lines.append(f' elif key == "{env_var}":') lines.append(f' script_values["{field_name}"] = value == "0"') elif field_name == "enable_wsi": - # Special case: ENABLE_GAMESCOPE_WSI=0 means enable_wsi=False + # Special case: ENABLE_GAMESCOPE_WSI=0 or DXVK_HDR=0 means enable_wsi=False lines.append(f' elif key == "{env_var}":') lines.append(f' script_values["{field_name}"] = value != "0"') + lines.append(f' elif key == "DXVK_HDR":') + lines.append(f' script_values["{field_name}"] = value != "0"') elif field_name == "enable_zink": # Special case: Zink uses multiple environment variables lines.append(f' elif key == "__GLX_VENDOR_LIBRARY_NAME" and value == "mesa":') @@ -161,9 +163,10 @@ def generate_script_generation() -> str: lines.append(f' if config.get("{field_name}", False):') lines.append(f' lines.append("export {env_var}=0")') elif field_name == "enable_wsi": - # Special case: enable_wsi=False should export ENABLE_GAMESCOPE_WSI=0 + # Special case: enable_wsi=False should export ENABLE_GAMESCOPE_WSI=0 and DXVK_HDR=0 lines.append(f' if not config.get("{field_name}", False):') lines.append(f' lines.append("export {env_var}=0")') + lines.append(f' lines.append("export DXVK_HDR=0")') elif field_name == "enable_zink": # Special case: enable_zink=True should export multiple Zink environment variables lines.append(f' if config.get("{field_name}", False):') -- cgit v1.2.3