Love2D: You can open an image from anywhere

It seems a common misconception that images cannot be loaded from outside of the source code directory, but you can. Love’s love.graphics.newImage function doesn’t accept file paths outside of the source directory, but it’s pretty easy to work around.

Assume the following file structure:

working directory/
  src/
    main.lua
  image.png

And here’s the code that will load that image:

-- images must be opened in binary mode
local file = io.open("image.png", "rb")
local data = file:read("*all")
file:close()

local byte_data = love.data.newByteData(data)
local image = love.graphics.newImage(byte_data)

I see people running into this problem all the time and no one seems to dig deeper. While it’s bad practice for many uses to do this, sometimes it’s necessary. For example, I made a little mapping program that can load maps from drag-and-drop – which always means files outside of the source directory.

AI Coding Tools Influence Productivity Inconsistently

Not So Fast: AI Coding Tools Can Actually Reduce Productivity by Steve Newman is a detailed response to METR’s Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity study. The implied conclusion is AI tools decrease productivity by 20%, but this isn’t the only conclusion, and more study is absolutely required.

[This study] applies to a difficult scenario for AI tools (experienced developers working in complex codebases with high quality standards), and may be partially explained by developers choosing a more relaxed pace to conserve energy, or leveraging AI to do a more thorough job.
– Steve Newman

Under the section Some Kind of Help is the Kind of Help We All Can Do Without is exactly what I’d expect: The slowdown is attributable to spending a lot of time dealing with AI output being substandard. I believe this effect can be reduced by giving up on AI assistance faster. In my experience, AI tooling is best used for simple tasks when you verify the suggested code/tool usage by reviewing manuals/guides, or when you only use the output as a first-pass glance to see what tools/libraries you should look up to better understand options.

To me, it seems that many programmers are too focused on repetitively trying AI tools when that usually isn’t very effective. If AI can’t be coerced into correct output within a few tries, it usually will take more effort to keep trying than to write it yourself.


I wrote the following from the perspective of wanting this study to be false:

There are several potential reasons for the study results to be false, and these pitfalls were accounted for, but I feel some arguments were not well-supported.

  • Overuse of AI: I think the reasoning for why this effect wasn’t present is shaky because it reduced the sample size significantly.
  • Lack of experience with AI tools: This was treated as a non-issue, but relying on self-reporting to make that determination, which is generally unreliable (which was pointed out elsewhere). (Though, there was not an observable change over the course of the study, indicating changing experience is unlikely to affect the result.)
  • Difference in thoroughness: This effect may have influenced the result, but there was no significant effect shown either way. This means more study is required.
  • More time might not mean more effort. This was presented with nothing to argue for or against it – because it needs further study.

(The most important thing to acknowledge is that it’s complex, and we don’t have all the answers.)

Conclusions belong at the top of articles.

Studies are traditionally formatted in a way that leaves their conclusions to the end. We’ve all been taught this for essay writing in school. This should not be carried over to blog posts and articles published online. I also think this is bad practice in general, but at least online, where attention spans are their shortest, put your key takeaways at the top, or at least provide a link to them from the top.

Hank on vlogbrothers explains how the overload of information online is analogous to how nutrition information is overwhelming and not helpful. (This hopefully explains one of the biggest reasons why the important stuff needs to be clear and accessible.)

Writers have a strong impulse to save their best for last. We care about what we write and want it to be fully appreciated, but that’s just not going to happen. When you bury the lead, you are spreading misinformation, even if you’ve said nothing wrong.

Putting conclusions at the end is based on the assumption that everyone reads the whole thing. Almost no one does that. The majority look at a headline only. The next 99% only read the beginning, and the next group doesn’t finish it either. A minority finishes reading everything they start, and that’s actually a bad thing to do. Many things aren’t worth reading ALL of. Like this, why are you still reading? I’ve made the point already. This text is fluff at the end, existing to emphasize a point you should already have understood from the rest.

How to check if ANY browser is installed in Linux (even more updated)

Updated: 2025-06-12
(If you just want to know my solution, skip to Reading .desktop Files.)

Linux is a very powerful operating system that gets more user-friendly by the year, but it still has glaring holes. Today, I discovered there is no reliable method to finding out if a browser is installed.

Searching online reveals that most people only care about knowing if specific browsers are installed, or are content with the incomplete option of only checking for the most popular browsers (currently Chrome, Firefox, and Opera). The which command works fine combined with a resource like LinuxConfig.org’s List of Browsers available on Linux, but now your script requires periodic maintenance to add more browsers to the list1.

The next most common answer online is to see if xdg-open exists, based on the assumption that a browser must be installed if xdg-open is installed – this is simply false. You also can’t query xdg-open to see if it can handle URLs without opening a URL. If you use this method, you are effectively attacking the user with a pop-up2.

I’ve also found documentation for update-alternatives, but it requires knowing exactly what name it uses for browser entries. I was told to use x-www-browser, gnome-www-browser, and just www-browser. None of these work, and the command doesn’t allow you to list all of its entries because the --all option forces you into an interactive session to configure every single option it has. I refuse to go through that mess just to find how browsers are defined.

This should be simple, shouldn’t it?

Worse, I’ve also found multiple users stating that this fails to adhere to system defaults on Ubuntu, despite it being Ubuntu’s official default method.. and it doesn’t even WORK.

There’s also Debian Wiki’s DefaultWebBrowser which is somehow too dense and too sparse, and in light of what I’ve already tried – nonsensical. Suggesting the use of a $BROWSER environment variable strikes me as particularly insane6.

The best option I can find right now is to manually scan every menu entry for programs categorized with WebBrowser3. This still excludes some options, is convoluted, and has the possibility of failing due to mistakes in menu entries. But it’s the closest to a future-facing solution I could find.

(While asking an unrelated question on the Linux Mint Forums, I did get more information about browser defaults, which you may find useful.)

Reading .desktop Files

Update: xdg-settings get default-web-browser basically has already done what I was doing here5. If anything has a .desktop file for a browser, that should return whatever default has been selected, thus telling you a browser is installed.4

Menus in Linux use a standard format to describe programs/actions so they can be automatically organized. Even some CLI apps create these entries as well. These are organized by predefined Categories, including WebBrowser. While this may still exclude some niche browsers, the users of such browsers likely will know how to handle this incompatibility, and are very very rare.

The only issue with this solution is finding the files and having to parse them yourself. This is still a little tedious, but will last longer and detect new browsers automatically. Unfortunately, the only information I found on where these files should be is conflicting slightly. The Arch wiki says they are in 3 specific locations, but the actual spec excludes one of those and specifies an environment variable where the rest are located. So I check all of these locations, scan every file, and look for two things: 1) A Categories key with “WebBrowser” in it. 2) No Hidden key.

For my specific use case, since I only need to know a browser is installed, I can exit this search on the first hit, but obviously you can use the spec to actually find which browsers are installed, and even launch them or show their icons!

For reference’ sake, here’s what a .desktop file for LibreWolf could look like:

[Desktop Entry]
Type=Application
Name=LibreWolf
Comment=Privacy-focused web browser
Exec=/path/to/librewolf
Icon=/path/to/icon.png
Categories=Network;WebBrowser;

What the hell am I doing this for anyhow?

I’m writing a script to help me automatically select and install packages on a Linux system so that I don’t have to remember or constantly look up how to install things that aren’t part of the standard package management of my system, or the names of things I may have forgotten about because I use them rarely.

The fundamental design of this script includes the ability to run installs and configurations in any order, except where dependencies require a specific order. Part of it removes Firefox due to Mozilla’s recent privacy violations7, another part adds a replacement browser, but other parts of the script require a functioning browser to function. Initially, I thought I just needed a check to see if any browser is present, but later I realized I need to be able to count how many browsers are installed. While I’m glad I found out there is a simpler way to check for any browser, I’m still using a manual scan of .desktop files because I need to count them.

(As I write this, I realize that while my current solution addresses most of my needs, I should have each browser-requiring section of the script verify a browser is present, instead of requiring the user to briefly have two browsers installed at once. While I still think it’s better to not remove a browser until its replacement is installed just in case, there is a hole in my dependency management here – especially because the user can do their own things outside of my script, obviously.)

Footnotes

  1. Any decision that adds future maintenance costs should be made very carefully and avoided if possible. Do you really want to devote a portion of the rest of your life to making sure this keeps functioning? Do you really want to limit your list of acceptable browsers to only what’s popular now?
  2. How long has it been and we still don’t force applications to open without stealing window focus at an OS level? There are always heavyweight applications, no matter how fast computers get, and computers are fundamentally designed for multitasking. We should be able to start a program and do something else while waiting for it to open, without the risk of random inputs being sent to the program when it is finally ready. Combine this with the fact that many programs steal focus before they’re even ready to accept input and it’s a garbage user experience.
  3. Thanks to Arran Ubels on StackOverflow for helping me find this answer.
  4. In theory, a browser could still be installed that has its desktop file in the wrong place, but then it is likely the system won’t recognize it for using open or similar commands anyhow. For my use case, that means it is not worth continuing to look for a browser being installed, but depending on what you’re doing, you may want to search further. Heck, if it’s really important, you might want to find every desktop file on the computer to check for a browser – though at that point you should probably just be doing something to ensure a browser is ready yourself instead of trying so hard to find an extant badly configured browser..
  5. Thanks to @CcxCZ on Telegram for telling me about this command! It’s really strange that it didn’t appear anywhere in my searches for information on this.
  6. It was pointed out to me that I should elaborate on this: Environment variables are easily manipulated and overwritten accidentally when they have simple names. (For a counter-example, I don’t worry about referencing $XDG_DATA_DIRS because it is unlikely to be screwed up.)
  7. A more aggressive take on it. While they can legally defend themselves on the basis of no evidence of violation occurring so far, so can every company that regularly destroys your privacy. Companies don’t remove assurances about privacy unless they’re going to stop protecting your privacy. Companies do not care about your privacy.

Updates

  • Updated 2025-06-12: Added a link to a thread on Linux Mint Forums that has additional information about default browsers.
  • Updated 2025-06-08: Added a section explaining why I’m doing this differently than the simple solution at the end.

Realms Half-Post-Mortem (from LD39)

I started writing this in September 2018, and didn’t get very far. It’s clear I will not finish it. That said, I do want a record of its existence here, so I’m publishing it now.


To describe it in one word, ambitious. An asynchronous web-based multi-user dungeon, that looks and feels like a terminal. Everyone starts in nullspace with 1 health. Kill players and take their souls to power up the other Realms to access them.

original welcome prompt
The original welcome message on Realms

As you can see, things were running perfectly well with no errors what-so-ever. Items were implemented, characters could see actions of others using a jury-rigged event system, and there was even a dummy that could be used to create souls!

Probably my biggest achievement was in flexibility I managed. That, or the fact that I put in a way to send me messages with the report command.

As with many of my game jam entries, I was overly ambitious and failed to deliver something complete. That said, I think it was at least an enjoyable experience to briefly search around in this pseudo-terminal.

When Open Source Maintainers Don’t Understand Community is Important

This is just to vent frustration at a thoroughly stupid experience I had recently. A portion of that stupidity is me failing to read something correctly, but I’m just really stuck on the stupidity of the response to me asking for help:

I asked for clarification, and was told to go away.

My reaction clearly indicates that I am not undrstanding something, and I even tried to give context to where I’m coming from so that it would be easier to spot what I misunderstood, but instead I was told to go ask a bot.

And then they blocked anyone from ever asking for help again.

The public is not allowed to open issues now.

What’s most frustrating to me about this is that it coincides perfectly with another issue I ran into today where I couldn’t add an important detail to an old issue. Past conversations are useful to people looking for assistance, especially when one solves their problem and explains it. When I am blocked from replying to something with a solution, anyone in the future experiencing the same issue is likewise blocked from finding the answer.

I now know what I messed up, but I’m not allowed to pass that knowledge to the future, because I was confused and made a mistake in how I asked for help.

There’s another layer to this that is often ignored: When this is the response the average newbie gets when they first try to contribute, they are encouraged to never ask again, or in the case of submitting pull requests, encouraged to never try to help again.

When open source maintainers discourage newbies, they cannibalize the future of their software.


Okay, that’s my entire point, but I also encounted some funny things as part of this.

What is a contribution? GitHub doesn’t know!

I think it’s interesting that GitHub says the repo limited opening issues / commenting on issues to past contributers, but I am a past contributer. GitHub clearly considers issues to be contributions, as every profile has a graph showing issues as part of their contributions:

My contributions: 89% commits, 11% issues.

AI tools can be very powerful, but they can also be very stupid

Earlier today, I tested Perplexity AI’s capability to answer a few basic questions easily answered through traditional search engines, such as which insect has the largest brain and which country is the current leader in development of thorium-based reactors. The results? It doesn’t know ants are insects, thinks fruit flies have large brains just because they have been the subject of a large number of studies, and ignores India in favor of China because western media reports on China a lot more.

But you know what, I wanted to test this asshole’s suggestion to ask ChatGPT about my problem, and surprisingly, it gave a very clear and accurate response!

ChatGPT points out what I misread: I have to clone the repo AND run NPM, not just run NPM.

When you offer binaries for a project, they have to actually exist..

To be fair, this is a fairly recent change to the ReadMe, but maybe you should publish binaries before advertising that you publish binaries?

Getting Started: Download a release binary and run it. Simple.
The advertised binaries don't exist.

Installation and usage aren’t the same thing

It’s understandable to be confused about whether someone has correctly installed something, but after confirming that installation has worked, ignoring the question asked is unhelpful to say the least.

After confirming that I've installed it, my question is ignored.

Updates
2024-10-02: Added a note when OpenAI removed access to websites.
2025-11-13: Removed that note because it was a temporary thing and I forgor.