Add Deck Shelves to Plugin Store#1018
Conversation
Issues Found
Next Steps
Thank you for your contribution! If you need any help, please reach out on our Discord server. ❤️ |
|
debug flag exists on code just for debug purposes, but is removed in my packaging script: if have to run this script on some specific flow decky build follows, please say me I'm using it on and |
|
Hi, 1- My favorites aren't displaying. I have 7 favorites, but nothing shows up on the home screen. Perhaps the selection is based on the collection name, which in my case must be French and in yours English? So the problem would occur for all languages. 2- I tried the "Recently Added" collection, but it doesn't seem to be sorted in that order. 3- The displayed covers don't use the style (rounded edges, for example). You can see that when I navigate, Steam games have a border radius when focused, but not the Steam games themselves (Cyberpunk 2077 is a non-steam game, Splitgate is a steam game). 4- When navigating the Steam row, the focus of the game I'm browsing is the middle one. If I scroll to the right, it scrolls to the left, but the selected cover is still the middle one. With your plugin, the selection goes all the way to the right before scrolling. 5- There's a sort of lag, more like a latency (but I don't know if it's Steam causing this or not) when I navigate to a line you added 6- Quite a few translations are missing Despite these points, the plugin is really clean and works very well. I expected some asynchronous loading with a delay before collections appeared, but that’s not the case. |
|
@moi952 Please only review plugins that have been deployed to the testing store. Withholding review on this plugin since the required action mentioned by GitHub Actions has not been completed. |
Sorry, I didn't know. This is the first time I've submitted a plugin, and especially the first time I've seen how it works overall. |
Our build CI just builds from the source that is in the file at present, so you will have to remove the debug flag in source. Additionally, it appears you have not properly linked the submodule as there is no new plugins being detected. |
|
@santojon Please make your submodule a path without spaces. |
Unless you use the backend folder to run a custom backend build process, you can't easily specify a shell script to run. I highly recommend removing the debug flag and using a shell script to build it with the flag instead. |
Both suggestions done ✅ @EMERALD0874 |
a3f7893 to
d45d7ea
Compare
Have tried here and now it seems to be ok. Can you try again? |
01f8cc0 to
41f1c6a
Compare
|
@EMERALD0874 @beebls |
|
Before we review this I just want to get a statement on how and if AI coding tools were used in the creation of this plugin. We can't approve plugins where AI was used to generate a majority of the code to the store due to issues around proving who owns the copyright to them. Majority is a bit of a subjective term of course, but we just want to know if you used AI coding tools during the plugin creation process, and if so, can you still vouch for both the originality, quality, and security of your code. |
|
Sure, I understand your concern. I used Github Copilot for internationalization into languages other than Portuguese, English, and Spanish, which are languages I don't master, to speed up documentation updates (with subsequent manual review) and the creation of diagnostic scripts and some other scripts that I revised later. All the functional part of the plugin (everything within /src) was done without the use of AI. |
EMERALD0874
left a comment
There was a problem hiding this comment.
LGTM for testing but will review the code closer at another point
For maintainers: Initial review looks like AI was used for supplementary purposes like documentation and translation, supporting the dev's claim. I'll look into this further at another point to be sure, given certain things were clearly AI-generated (e.g., branding) when they could've been created without it.
|
Branding image was generated using Chat GPT in project's initial phase, before start the development, it was a starter point for me to visualize and ideate about how it will look, but the real project after development looks very different. I can change or remove it if requested without problems. |
Plugin Testing ReportInstalled Plugins
Specifications
IssuesHas the following major blocking issue(s): None SummaryTested by creating custom shelves on the home screen and editing them via the Quick Access Menu. Custom shelves appeared correctly on the home screen below the native recents row. Steam collections loaded and displayed properly. Navigation between shelf items felt smooth and responsive. Overall a very well-built plugin that fills a gap in Steam Deck's functionality. Works as expected. |
Plugin Testing ReportInstalled PluginsDecky proton launch - 0.9.0 SpecificationsBazzite (Steam Deck mode) IssuesNo issues to report. SummaryI tested the plugin under normal usage conditions and everything works as expected. No bugs or conflicts observed with other installed plugins. |
beebls
left a comment
There was a problem hiding this comment.
Gonna second the approval here, all looks good


Add Deck Shelves to Plugin Store
Features
Deck Shelves — Project Overview
1. What it is
Deck Shelves is a plugin for Steam Deck (SteamOS GamepadUI) that injects custom shelves into the Home screen (
library/home), below the native "Recently Played" row. Each shelf is a list of games resolved from a source (a Steam collection, a library tab, or a custom filter) with its own visual options.The plugin also ships a full editor in the QAM (Quick Access Menu) for creating, editing, reordering, hiding, duplicating, importing and exporting shelves — without leaving the in-game UI.
2. Design principles
useEffect, listener and observer.src/runtime/homePatch.tsx,src/core/*,src/integrations/*— minimal, well-justified changes only.3. Features in detail
3.1 Custom shelves on Home
#deck-shelves-home-rootcreated byruntime/homePatch.tsxas a sibling of the native recents row.DeckRow— header with collapse/expand title (saved inlocalStorageunderds-collapsed-{id}) plus a horizontally-scrollable row ofGameCarditems.types.ts > ShelfSourceSchema):collection(Favorites, user folder,[Unifideck] Installed, etc.).tab(library tab, including tabs created by other plugins — runtime detection).filter(FilterGroup with nested AND/OR).3.2 Filter system (FilterGroup)
Schema in
types.ts > FilterGroupSchema: a tree ofFilterItems combined undermode: "and" | "or". Supported types:installed,favorites,nonSteam,hidden,updatePending,isNew,deckCompatibility,playedWithinDays,playtimeRange,nameIncludes,nameRegex,friends,storeTag,achievements,collection,developer,publisher,appIdList,cloudAvailable,controllerSupport,merge.cloudAvailablematches apps withbCloudAvailable === true;controllerSupportacceptsmin(default 1 = partial or full, 2 = full only) compared againstnControllerSupport. Both invertible.Sort:
alphabetical,recent,playtime,release_date,size_on_disk,metacritic,review_score,added,random,manual.Manual sort — when
shelf.sort === "manual"(orshelf.source.filter.sort === "manual"for filter sources),applyManualOrder(ids, shelf.manualOrder)insrc/steam/index.tsreorders the resolved ids byshelf.manualOrder: number[], with new ids (not inmanualOrder) ordered bymanualBaseSort.3.3 Per-shelf and global toggles
matchNativeSize— card dimensions match the native shelf (measured at runtime viacore/webpackCompat.ts > discoverNativeCardDimensions).highlightFirst/highlightAll— render the first / all cards as featured landscape.highlightedAppIds?: number[]— explicit list of appids to render as featured.manualOrder/manualBaseSort— whensort === "manual".hideStatusLine,hideNewBadge,hideCompatIcons,hideNonSteamBadge,hideShelfTitle,hideGameNames,hideInstallIndicator— fine-grained card element controls.3.4 Home-specific global toggles
hideRecents— hides the native recents row; when active, the first shelf is force-expanded.shelfHeroBackground— first shelf gets a hero background sourced from the focused card's art.hideHomeTabs— hides the home tab strip, identified dynamically via[role="tablist"]siblings near the mount.recentsReplaceSource— uses a Deck Shelves shelf as a drop-in replacement for the native recents row.3.5 Quick Access Menu (QAM)
Full editor in
components/DeckQAMSettings.tsx:enabledtoggle.ImportMenuButtoncollapses one entry to a direct icon, two or more to a[…]overflow), Export, Reset. Plugins register import types viaregisterImportTypeand show up in the same overflow menu.CollapsibleSectionhidden whensettings.savedFiltersis empty; inline rename + delete.3.6 Integrations
window.TabMasterStore+ reading itssettings.json.[Unifideck] Installedcollection.hideNonSteamBadge.3.7 Manual ordering + drag reorder
When
sort === "manual",EditShelfModalrendersManualSortRowin the Source tab. Pointer-hold drag (300 ms timer + move-cancel + hit-test) lives in theuseContainerDragReorder<T>hook insrc/core/reorder.ts— shared byManualSortRow, the QAM shelf list and the Home shelf-title drag. Gamepad grab (A toggles + L/R shifts viaFocusNavControllerpatch) stays inManualSortRow.Coexisting interaction modes
grabbedAppid = id; D-pad L/R shifts; A again releases.pointerdownarms a 300ms timer; on hold,pointermovehit-tests sibling cards;pointerupreleases.ReorderableShelfListcarriesdata-ds-shelf-row={id}and usesuseContainerDragReorder; up/down buttons coexist.ShelvesContaineruses the same hook withitemSelector: '.ds-shelf[data-shelfid]'andallowedPointerTypes: ['mouse', 'touch'].3.8 Crash protection
HomeBoundarywrapsHomeShelves; on error the mount is cleared and state is published.markReplaceFailed) — scoped torecentsReplaceSource.3.9 Smart Shelves
Heuristic-driven shelves. 16 modes: 15 heuristic templates +
custom(userfilterGroup+sort, no built-in heuristic). Master togglesmartShelvesEnabledin the QAM.SmartShelfschema:{ id, title, mode, enabled, hidden, limit?, sort?, manualOrder?, manualBaseSort?, filterGroup?, matchNativeSize?, highlight*, hide*, refreshIntervalMinutes?, smartParams?, visibleHours?, visibleDaysOfWeek? }.resolveSmartShelf(mode, apps, limit, params, ttlMs, shelfId?)insrc/steam/smartShelves.ts: pure, no side effects; silent failure (returns[]). Cache TTL ~5min, namespaced byshelfIdfor per-shelf isolation.Surprise Me — picks N modes randomly with a daily seed (consistent within the day, no state).
smartParams: each mode exposes editable parameters (sliders / dropdown / text inputs).minDeckLevel(0-3, per-mode default) is a dropdown with localized labels; playtime params (maxPlaytimeMinutes/minPlaytimeMinutes) are text fields with a draft buffer.Visibility window —
visibleHours: Array<{start, end}>OR-combined with wrap-around;visibleDaysOfWeek: number[](undefined= no restriction,[]= never visible).HomeInjectfilters out shelves outside the window and schedules a one-shotsetTimeoutfor the next boundary.3.10 Internationalization
16 complete locales:
en-US,pt-BR,pt-PT,es-ES,es-419,fr-FR,de-DE,it-IT,ru-RU,pl-PL,nl-NL,tr-TR,uk-UA,ja-JP,ko-KR,zh-CN.validate-compat.shchecks key consistency.Task Checklist
Developer
Plugin
Backend
Community
Testing