Had a realization as I was reading an interview with someone who loves programming recently: some of the hype over LLMs is because many programmers don’t enjoy programming and are relieved not to have to do it anymore
I had Claude implement a Vulkan backend for raylib that beats the OpenGL backend in runtime speed for every general use case. Except two.
I've been pulling off some pretty crazy shit in record time that simply would be impossible pre-AI. A lot of people seem to be struggling with accepting this. Unfortunately, I cannot openly post things related to my real work. So decided to burn some Claude tokens on my personal account over the weekend and apply all I have learned to something which I could openly post.
First, I had Claude generate a system to run image equivalence tests on every deterministic raylib example:
https://t.co/wNJPPfGJaL
It goes through and output three images from each deterministic example it equal steps. Also relies on a change in rcore to force the timesteps to be controllable. All the images from the current rlgl implementation are saved in image_equivalence/rlgl_baseline
Then I fed Claude the entire Vulkan spec.
I also fed it a bunch of pedantic instructions on the style I write Vulkan with a bunch of my personal C Vulkan code. For example, if you look at the generated Vulkan code and say WTF are all the info struct inlined into the Vulkan calls with compound literals!? That's not claude. That's me :) It would produce a very different style on it's own.
Also told it to match the naming and comment style of existing rlgl and the try to produce similar file structure to rlgl.
Instructed it on how to edit the file, how to build, how verify a test passes, what to do when a test passes, what to do when a test fails. Then let it cook for several hours.
The first Vulkan backend it produced was actually slower than rlgl. Largely because I told it to use all of the newest Vulkan extensions it possibly could and it only needs to run on n NVidia 4090. Which led it to use the VK_EXT_shader_object extension and avoid VkPipelines entirely. Which turns out VK_EXT_shader_object is 3x-4x slower than the NVidia OpenGL driver for doing the same kind of dynamic renderer. Good to know! I actually didn't know VK_EXT_shader_object sucked so bad until I did this.
At which point I then instructed it on how to set up performance tests. Which are in the raylib_tests/performance folder. Taking several of the heaviest examples, and synthesizing a few new ones, to cover a wide range of graphical scenarios.
Then I instructed it on how to build, edit, run those performances tests. Also instructed it on how to break out isolated spike projects to test comparable Vulkan features and OpenGL features in isolation to find which specific ones by themselves are faster in Vulkan. Then use those Vulkan features proven in isolation to be faster to then design an entire Vulkan backend which could pass all of the image equivalence test. Then instructed it to iterate on this until every performance was faster the OpenGL backend. Giving it free reign to discern which exact Vulkan features to use so long as the testing showed it to be faster than OpenGL.
Then instructed it once it found an architecture that is faster to OpenGL. Then run all the image equivalence tests again to ensure they all still pass.
Rinse and repeat until all image equivalence tests are passing and all performance tests are beating opengl.
It then cooked for another several hours or so and produced the output I have committed in this branch:
https://t.co/TO8GT6qE97
Here is the performance test overview:
https://t.co/KbgYwNtJ7X
The one where OpenGL still beats Vulkan by a significant margin is the raymarching example. Not because of Vulkan. But supposedly because the Nvidia OpenGL driver is faster at executing shader code, so when you have a scene where the bottleneck is entirely in the shader fragment section, the Nvidia OpenGL driver can execute that faster than the Nvidia Vulkan driver. Which I also didn't know.
Also of note, despite the runtime performance being better, the RAM and VRAM usage is a little worse. Which has to do with the baseline of the Nvidia Vulkan Driver being worse than the Nvidia OpenGL Driver. However, I'd expect this to completely different on Linux and AMD.
Aside from being able to autonomously produce a usable backend for raylib. I found this exercise to be significant because, ultimately the performance of raylib rlgl is not so much rooted in rlgl as it is rooted in Nvidia's OpenGL driver. Which is really good. There are a couple decades of careful manual optimization put into the Nvidia OpenGL driver to make it super performant for that style of renderer. Which Claude could figure out how to beat with Vulkan.
Now what exactly is the code like?
C99 and Vulkan are very formulaic. When everything is structs and methods, there is a lot less room for it to do 'crazy shit' with architecture. Also, between raylib's rlgl which is very well patterned and consistent, and my personal Vulkan code which is also very specifically opinionated, it had a lot of specific, explicit, pattern to follow.
Glancing over the resultant generated code I'd say, I'd probably significantly change about a quarter of it manually. Cleanup and rearrange. Rewrite some of the methods. Maybe instruct on some different struct layouts and relationships to use. Give it some different foundational data structures to use. Which, since Claude is aware of everything in here, I could radically rearrange all the struct layouts, and data relationships, and layout new data structures. Then prompt Claude, "I changed all of this ____ make the code work with it", and it would. Reworking all the methods to match the new data design probably in about 10 minutes.
Probably the roughest part is where it did reflection on SPIRV to figure out how to wire the existing GLSL OpenGL shaders to Vulkan. There is nothing like that in all of my Vulkan code so it was on its own there. I might spend a day going over that.
Which after that, it'd arrive me at about the same result had I done everything manually. But in about 4 days instead of what would have probably been 4 months. Most of which would have been a lot of formulaic boring testing, trial and error which I'd rather not do.
Given all of that. If you code generated with Claude is crap and you can do better. Well then by all means, produce some evidence by implementing a vulkan backend for raylib that beats this :) That would be a worthy donation to open source. That is of course if you can actually do it and you aren't just bullshitting everyone when you say you can do better than AI.
Spotify ships 4,500 prod deploys/day. One every 19 seconds. Can't they wait 19 seconds to batch two changes together? That's not velocity, that's a planning failure wearing a CI/CD costume. It's not continuous deployment, it's a slot machine that occasionally plays music 😭
Creator of Sqlite on pull requests: "You say, oh, it's free. No. It's not free. What you're doing is asking me ... to maintain it for you, to to document it for you, to test it for you, to maintain it for you for the next 25 years. That's not free." Yep.
Wise words from a wiser man than me. I've told people for the past decade and I have recent posts on here saying the same: the merge button is the easy part. Its the decade+ (Richard says 25 years) that follows where you've accepted the transfer of maintenance thats hard.
Finally got to ~zero input-to-display latency on macOS. It has taken us a _lot_ of work to get here!
This is a slow-motion capture of a 120 Hz screen running a playbit program that draws a rectangle where the cursor is.
The slight lag you're seeing is not from rendering latency but from "old" mouse position data (we receive it from macOS window server in a event queue.)
Remember that the mouse cursor is drawn with dedicated hardware (dedicated GPU plane) so dragging a rectangle is the ultimate input-to-display latency test.
@championswimmer@ponnappa The worst part about being able to tell bad code from good code is that "good" is counterintutive: it's so simple you almost start wondering why it's so simple, surely there's a hidden missing edge-case, surely it should be more complex.
So now you're stuck having to explain it.
Every time I see a team celebrating their new "shared module," I remember this lesson.
Reuse is a dangerous form of coupling.
They found the same logic in two places and did what good engineers do: put it in one place and called it a win. Clean, responsible, textbook.
Six months later, someone needs to change it.
Suddenly, a small update for one team's requirements breaks three services, blocks two releases, and triggers an emergency meeting between people who've never talked to each other before.
This is the cost nobody preaches about.
DRY is one of those principles that feels unquestionably right until you apply it across team boundaries. The moment you share a module between domains, you're not just sharing code. You're creating a dependency that nobody owns and everyone resents.
Before you reuse, ask:
Will this change often?
Does it belong to one domain?
Are the consumers truly aligned in purpose?
Will one team’s change surprise another team?
If the answer to any of these is "I'm not sure," stop. Duplicate it.
I know how that sounds. It feels lazy. It feels like the thing a junior developer does before they know better. But here's what nobody wants to say out loud: two independent implementations you control are almost always cheaper than one shared one serving masters with different goals.
Duplication is a local problem. Coupling is an organizational problem.
One of them you can fix in an afternoon. The other requires a meeting with five teams and someone's manager.
Reuse isn't free. Treat it like the trade-off it is.
@FatalError1609@KasemSM_ I know right, MVI was shady even in 2016, and somehow people still willfully choose to overcomplicate their design 10 years later
And the wildest part is when they grab a third-party framework to do it (e.g Orbit) due to thinking: "if it's there, surely it's good for something".
Complexity is often a byproduct of inefficient categorization or a failure to identify the primary governing principle. Clarity occurs when a system is reduced to its essential components. Redundancy and emotional noise obscure functional truth.
Act on press
This is a UI design hill I will die on, and it dismays me how often and hard I have had to fight for it.
Almost all interaction methods have a “press” and “release” event associated with them. Whenever possible, you should “do the thing” when you get the press event instead of waiting for the release event, because it makes the interaction feel substantially more responsive, and it reduces user errors by not allowing the focus to slide out of the hot box between press and release.
Even a “ballistic tap”, where your finger is intentionally bouncing off the button or touch surface, involves several tens of milliseconds delay between the press and release, and most button presses have well over a hundred ms dwell time. There is a delight in interfaces that feel like they respond instantly to your wishes, and the benefit to every single user is often more important than additional niche features.
Game developers, with simple UI toolkits, tend to get this right more often, but “sophisticated” app designers will often fight hard against it because it is mostly incompatible with options like interactive touch scrolling views, long press menus, and drag and drop.
Being able to drag scroll a web page or view with interactive controls in it is here to stay, and nets out way better than having to use a separate scroll bar, but there are still tons of fixed position controls that should act on press, and it is good UI design to favor them when possible.
In the early days of mobile VR, the system keyboard was a dedicated little OpenGL app that responded instantly. With full internationalization it became prudent to turn it into a conventional Android app, but the default act-on-release button behavior made it feel noticeably crappier. The design team resisted a push to change it, and insisted on commissioning a user study, which is a corporate politics ploy to bury something. I was irritated at how they tried to use leading questions and tasks, but It still came back one of the clearest slam-dunks I have seen for user testing – objectively less typos, expressed preference, and interview comments about the act-on-press version feeling “crisper” and “more responsive”.
So, I won that one, but the remaining times I brought it up for other interfaces, I did not, and you still see act-on-release throughout the Meta VR system interfaces.