Releases: ArdaYalinOzkan/parallax-launcher
Releases · ArdaYalinOzkan/parallax-launcher
Release list
3.7.0
Give the library a door that is not a window
A command line, because a program asked to put a game on had no way in.
The library is a text file it would have had to learn the format of, and
starting a game means knowing about Proton, Steam ids and compatibility
tools — all of which this codebase already knows and none of which it
was willing to say out loud. Now it is reachable:
parallax-launcher --cli games --json
It lives inside the copy of Parallax already installed rather than in a
second program to install, opens no window and needs no display, so it
works over SSH and inside a container. Read the library, start a game,
add an entry, change a field, ask where a game is, ask Steam what is
really installed.
What it deliberately cannot do is delete a game or touch an account.
Those are the operations that cannot be taken back, and they are absent
rather than discouraged: something that reads a web page and decides
from it what to do next should not be holding them. Everything here is
either read-only or a change a person can undo in the window.
Which raised a question the app had never had to answer. Two things now
write to one file, and the window keeps the whole library in memory and
writes it out whole — so an edit made outside would have lived until the
next save and then vanished under an older copy, with nobody ever seeing
what happened. The file is watched now, and a change the app did not
make is read back within a second. Its own writes are marked as they
happen so it does not chase its own tail, and a game being edited at
that moment is left alone: the person holding it keeps it.
Also: how much room a game takes now sits beside its status rather than
in a column of its own, since a column reading "—" for every game you
have not installed is mostly empty space asking to be looked at. And on
Windows the installer has earned enough reputation that SmartScreen no
longer stops it, so the warning has come off the download page and the
guide that explained how to get past it is now a short note in case a
future release starts as a stranger again.
3.6.0
Let the library answer for itself Four things a person had to do by hand, that the program knew how to do all along. Sorting by cover colour. The artwork is already on disk and already decoded at start-up; reading the dominant hue out of it costs nothing more, and a shelf arranged by colour is a shelf you can find things on by eye. Hues are averaged as vectors on the wheel rather than as numbers, because 350° and 10° are neighbours and their arithmetic mean is not. Covers with no colour worth speaking of go to the end, by name. "Default" is gone from the sort list — it meant "the order they happened to be added", which is nobody's idea of an order — and Play Time takes its place as the one that opens. How much room a game takes. Measured by walking the folder rather than asking Steam, since a game somebody pointed at by hand has no Steam record and the question is the same either way. Bounded by a file budget: a modded install can hold hundreds of thousands of files and nobody wants a page that waits on a filesystem. Where a game is. Adding one used to mean finding its folder yourself, which sounds easy until you try it: the folder is rarely named after the game, it is often on a second disk, and every shop puts it somewhere else. Steam's own manifest answers it exactly when there is an appid; everything else is a search of the places games are kept, including C:\XboxGames, which is where Flight Simulator lives and where nobody thinks to look. The old version of this knew one hard-coded Steam path and matched folder names against titles character for character, which is to say it almost never worked. And the button on a game that is not installed. It offered to install whatever had a Steam id, whether or not the account owned it — so a game shared through a family, or bought somewhere else entirely, led to Steam refusing a request it could not honour and the person standing in front of a button that would not work. It now looks on this computer first and only turns to Steam if the game is genuinely not here. When it is not, the choice between downloading and pointing at an existing copy is a real choice, so it gets asked rather than guessed. Internal Notes is removed. Every note the program ever wrote there was the same sentence, nobody had typed anything else, and a field carried for years by inertia is worth less than the space it takes. The text goes from everyone's library file on first run; anything that was not that boilerplate is copied out to notes-backup.txt beside it first, because deleting is the instruction and doing it without leaving a way back is not. Also: play time on a game's page was showing Steam's raw float — 79.7167 Hours, when the cards had been rounding it all along. The file keeps its precision; the page rounds, and hands the unrounded value back when you edit it, so saving cannot quietly file down anyone's hours a minute at a time. And the file picker offered .exe and nothing else, which on Linux hid exactly the files somebody was looking for. Two things outside the program. The NOTICE now declines to license the name and logo under section 7(e): the code is free to take, the name is not, and a fork ships under one of its own. And every released file now carries a signed build attestation naming the commit and the workflow that produced it — readable source says what the code does, this says the download is that code.
3.5.1
Let the loading screen be seen It was held for at least 900ms so it could not flicker past. On this machine the work often finishes sooner than that, so what people actually saw was a flash — which tells them nothing and looks like a fault. Three seconds now. It is longer than the work usually needs and that is the point: the app is doing something on their behalf, and this is the one place it says so. A launcher that opens instantly and then stutters feels worse than one that takes a moment and then does not.
3.5.0
Load it all at the start, so nothing loads later The loading screen was doing half a job: it warmed the first sixty covers when an account was picked, which left a second wait in the middle of using the app and still left every game page to fetch its own banner. There is one wait now, at launch, and it does the whole thing. Every account's art is gathered and warmed behind that screen — which account somebody will pick is not knowable at start-up, and warming the wrong one is worse than warming none. Covers are decoded, because the shelf paints them the instant it appears. Banners are only fetched: a screen-sized picture costs several megabytes decoded and there is one per game, so holding them all would cost more than it saves. With the bytes already here, opening a game page decodes one in a few milliseconds. Picking an account no longer shows a loading screen at all. It has nothing left to do. Measured after the veil lifts, longest frame in each: library 100ms first game 67ms game 120 of 216 33ms game 215 of 216 33ms settings 67ms The last two are the point: a game deep in the list opens exactly as smoothly as the first. Also — a Steam game uninstalled through Steam went on showing as installed no matter how often the library was refreshed. The check asked whether the folder was still there, and Steam leaves it behind, empty. Steam's own appmanifest_<id>.acf is the authority for a Steam game and is used now; a game pointed at by hand is still judged by its folder, which is the only thing there is to judge it by. Three games here were wrong; the refresh corrects them.
3.4.0
Do the waiting before the animation, not underneath it Every screen was worst the first time, and every attempt to shave that down ran into the same wall: the work is real, and something has to absorb it. So the app now says so. A loading screen carries the mark and wordmark the account screen already wears, plus a bar, and it is up from the very first frame — nothing is shown part-drawn and then animated over. It covers two waits. At launch it holds until start-up has finished and the account screen is painted. On picking an account it returns, decodes the first sixty covers with the bar moving, swaps the screens underneath itself, and only then lifts. What used to be a stuttering transition is now a veil rising off a library that is already finished. Three things had to be true for that to work. The veil sits at 0.999 opacity rather than 1. A fully opaque element covering the window lets the browser skip painting everything behind it, so the library was not drawn until the veil began to fade — putting its most expensive frame in the middle of the only animation anybody sees. At .995 the account screen showed faintly through; at .999 nothing does, and the shelf paints while still hidden. Only sixty covers are decoded up front. All two hundred takes about eight seconds, which is not a wait worth imposing to prevent a stutter, and the stutter only ever came from the first screenful. The rest, and every banner, are fetched afterwards in small batches with a pause between them — draining that queue as fast as idle time allowed stalled a frame for half a second a moment after the library appeared, and idle work anybody can see is not idle work. A game page opened after the warming has finished shows no long tasks at all. And the veil stays up for at least 900ms even when the work finishes sooner, because a loading screen that comes and goes inside a blink reads as a glitch. Measured across the entry: stalls now land before the veil lifts. After it, the longest frame is 50ms.
3.3.3
Stop the first visit to a screen from stuttering
Walking into the library, settings or a game page for the first time
jerked; the second time was smooth. That gap is the whole diagnosis —
the cost is work each screen does once, and it was landing on top of
the animation.
Measured, first visits, before and after:
library 55 frames / 5 stalls / 613ms of long tasks
→ 101 frames / 2 stalls / 177ms
settings 68 frames / 4 stalls → 68 / 2
again 68 frames / 7 stalls → 75 / 1
game page 63 frames / 6 stalls → 70 / 4
Four changes. Covers are lazy and decode off-thread, so a shelf of two
hundred no longer decodes two hundred pictures to show twelve.
content-visibility lets the browser skip laying out the cards below the
fold at all. The shelf is built in a fragment and put in once instead of
appended card by card. And the game page measured its banner on a 450ms
timer, which put the most expensive frame of the visit exactly halfway
through the transition — it hangs off the end of the transition now,
same work, nothing moving.
A fifth change was tried and reverted with a comment left behind:
moving will-change off the cards and onto :hover, which is the usual
advice, made the library go from 4 stalled frames to 47. The cards sit
under a backdrop-filter whenever a dialog opens, and filtering
unpromoted content rasterises the whole shelf every frame.
Also: opening one game straight after another showed a flash of the
previous game's banner, because an <img> keeps its old picture until
the new one decodes. It is hidden until the new one is ready and fades
in. Sampled every 25ms across the switch: no frame shows the old one.
3.3.2
Let dialogs close the way they open Two separate faults with the same cause: the animation was in the wrong place. Opening faded the whole modal by animating its opacity. An element with animating opacity becomes its own compositing layer, and the backdrop-filter inside has nothing to sample until that layer settles — so the window slid in clear and the blur landed afterwards, in one step. Closing set `display: none`, which cannot be animated at all. Window and blur went together, mid-frame, with nothing in between. Neither animates the modal now. The overlay fades and un-blurs on its own curve, the panel moves on its own, and the modal itself only stops taking clicks — its visibility switch is delayed past the transition so both children are still on screen while they leave. Measured on the way in and out: blur and panel travel together, 0 to 7px and back over 240ms.
3.3.1
Let the shelf show through behind a dialog blur(16px) over 74% black wiped the library out entirely. Both dialogs were already using the same rule, so the update box only looked heavier than settings because it is small and leaves far more background in view — the value was the same, the impression was not. Eased to blur(7px) over 58%, which both share. The covers behind are recognisable again without competing: the dialog still sits plainly in front of them.
3.3.0
Open in about a second and a half instead of three The window took 2.9s to appear, and 2.1s of that was the renderer. Almost all of it was one line: the page asked Google for Inter and JetBrains Mono, and that request blocked the first paint. A desktop program sat waiting on a network round-trip before it could draw anything — and offline it wore whatever the system had instead. Both faces are in the app now, variable-weight woff2, Latin and Cyrillic only: 240 KB for the eight languages that use them, with Chinese and Korean falling through to the system as they always did. There were two requests, not one — a <link> in the head and an @import at the top of styles.css — which is why the timings came in bimodal until the second one was found. Median to a usable window is now 1.41s across six runs, and nothing leaves the machine. The Steam catalogue fetch at startup is gone with it. It called an endpoint that has returned 404 for some time, to fill a cache whose only reader the renderer never calls. Updating happens where it starts. The dialog used to close itself and drop you into Settings to finish the download; now it carries the status line, the progress bar, Restart, and the automatic-check switch itself, and the panel in Settings still has all four — one set of actions driving both. The release notes are gone from both: they are written for the commit log, arrived with their own markup showing through as text, and said nothing a person at that moment wants. And the cards keep the tilt as you sweep along a shelf. Each one now has an invisible box 10px larger on every side, just under half the gap, so crossing between two no longer drops the highlight — and no pixel belongs to two cards. Padding would have done it too, but box-sizing is border-box here, so it took those pixels out of the cover instead of adding them outside it.
3.2.4
Stop the app from deleting menu entries it did not write It swept the whole applications directory for any entry whose command named a Parallax AppImage that was no longer there, and removed it. That was a wider reach than the job needed. Deciding that somebody else's menu entry is rubbish is not the app's business, and a mistake there is invisible until the day the entry is missing. It also could not do the job it was written for. There is exactly one entry, rewritten on every launch, so it cannot go stale while the app still runs — and once the file is deleted the app never runs again. That case belongs to the uninstall instructions on the site, which name the two files to remove. The whole function is gone. The comment above installDesktopEntry says why, so it does not come back.