The best Hacker News stories from Show from the past day
Latest posts:
Show HN: Rv, a Package Manager for R
We have been building a package manager for R inspired by Cargo in Rust. The main idea behind rv is to be explicit about the R version in use as well as declaring which dependencies are used in a rproject.toml file for a given project. There's no renv::snapshot equivalent, everything needs to be declared up front, the config file (and resulting lockfile) is the source of truth. This avoids issue where renv might miss information about the installation and is also easy to tweak some packages, eg install one from source and install suggests from another.<p>If you have used Cargo/npm/any Python package manager/etc, it will be very familiar.
Show HN: I built a knife steel comparison tool
Hey HN!<p>I'm a bit of a knife steel geek and got tired of juggling tabs to compare stats. So, I built this tool: <a href="https://new.knife.day/blog/knife-steel-comparisons/all" rel="nofollow">https://new.knife.day/blog/knife-steel-comparisons/all</a><p>It lets you pick steels (like the ones in the screenshot) and see a radar chart comparing their edge retention, toughness, corrosion resistance, and ease of sharpening on a simple 1-10 scale.<p>It's already been super handy for me, and I thought fellow knife/metallurgy enthusiasts here might find it useful too.<p>Would love to hear your thoughts or any steel requests!<p>Cheers!
Show HN: I built a knife steel comparison tool
Hey HN!<p>I'm a bit of a knife steel geek and got tired of juggling tabs to compare stats. So, I built this tool: <a href="https://new.knife.day/blog/knife-steel-comparisons/all" rel="nofollow">https://new.knife.day/blog/knife-steel-comparisons/all</a><p>It lets you pick steels (like the ones in the screenshot) and see a radar chart comparing their edge retention, toughness, corrosion resistance, and ease of sharpening on a simple 1-10 scale.<p>It's already been super handy for me, and I thought fellow knife/metallurgy enthusiasts here might find it useful too.<p>Would love to hear your thoughts or any steel requests!<p>Cheers!
Show HN: SQL-tString a t-string SQL builder in Python
SQL-tString is a SQL builder that utilises the recently accepted PEP-750, <a href="https://peps.python.org/pep-0750/" rel="nofollow">https://peps.python.org/pep-0750/</a>, t-strings to build SQL queries, for example,<p><pre><code> from sql_tstring import sql
val = 2
query, values = sql(t"SELECT x FROM y WHERE x = {val}")
assert query == "SELECT x FROM y WHERE x = ?"
assert values == [2]
db.execute(query, values) # Most DB engines support this
</code></pre>
The placeholder ? protects against SQL injection, but cannot be used everywhere. For example, a column name cannot be a placeholder. If you try this SQL-tString will raise an error,<p><pre><code> col = "x"
sql(t"SELECT {col} FROM y") # Raises ValueError
</code></pre>
To proceed you'll need to declare what the valid values of col can be,<p><pre><code> from sql_tstring import sql_context
with sql_context(columns="x"):
query, values = sql(t"SELECT {col} FROM y")
assert query == "SELECT x FROM y"
assert values == []
</code></pre>
Thus allowing you to protect against SQL injection.<p>As t-strings are format strings you can safely format the literals you'd like to pass as variables,<p><pre><code> text = "world"
query, values = sql(t"SELECT x FROM y WHERE x LIKE '%{text}'")
assert query == "SELECT x FROM y WHERE x LIKE ?"
assert values == ["%world"]
</code></pre>
This is especially useful when used with the Absent rewriting value.<p>SQL-tString is a SQL builder and as such you can use special RewritingValues to alter and build the query you want at runtime. This is best shown by considering a query you sometimes want to search by one column a, sometimes by b, and sometimes both,<p><pre><code> def search(
*,
a: str | AbsentType = Absent,
b: str | AbsentType = Absent
) -> tuple[str, list[str]]:
return sql(t"SELECT x FROM y WHERE a = {a} AND b = {b}")
assert search() == "SELECT x FROM y", []
assert search(a="hello") == "SELECT x FROM y WHERE a = ?", ["hello"]
assert search(b="world") == "SELECT x FROM y WHERE b = ?", ["world"]
assert search(a="hello", b="world") == (
"SELECT x FROM y WHERE a = ? AND b = ?", ["hello", "world"]
)
</code></pre>
Specifically Absent (which is an alias of RewritingValue.ABSENT) will remove the expression it is present in, and if there an no expressions left after the removal it will also remove the clause.<p>The other rewriting values I've included are handle the frustrating case of comparing to NULL, for example the following is valid but won't work as you'd likely expect,<p><pre><code> optional = None
sql(t"SELECT x FROM y WHERE x = {optional}")
</code></pre>
Instead you can use IsNull to achieve the right result,<p><pre><code> from sql_tstring import IsNull
optional = IsNull
query, values = sql(t"SELECT x FROM y WHERE x = {optional}")
assert query == "SELECT x FROM y WHERE x IS NULL"
assert values == []
</code></pre>
There is also a IsNotNull for the negated comparison.<p>The final feature allows for complex query building by nesting a t-string within the existing,<p><pre><code> inner = t"x = 'a'"
query, _ = sql(t"SELECT x FROM y WHERE {inner}")
assert query == "SELECT x FROM y WHERE x = 'a'"
</code></pre>
This library can be used today without Python3.14's t-strings with some limitations, <a href="https://github.com/pgjones/sql-tstring?tab=readme-ov-file#pre-python-314-usage">https://github.com/pgjones/sql-tstring?tab=readme-ov-file#pr...</a>, and I've been doing so this year. Thoughts and feedback very welcome.
Show HN: SQL-tString a t-string SQL builder in Python
SQL-tString is a SQL builder that utilises the recently accepted PEP-750, <a href="https://peps.python.org/pep-0750/" rel="nofollow">https://peps.python.org/pep-0750/</a>, t-strings to build SQL queries, for example,<p><pre><code> from sql_tstring import sql
val = 2
query, values = sql(t"SELECT x FROM y WHERE x = {val}")
assert query == "SELECT x FROM y WHERE x = ?"
assert values == [2]
db.execute(query, values) # Most DB engines support this
</code></pre>
The placeholder ? protects against SQL injection, but cannot be used everywhere. For example, a column name cannot be a placeholder. If you try this SQL-tString will raise an error,<p><pre><code> col = "x"
sql(t"SELECT {col} FROM y") # Raises ValueError
</code></pre>
To proceed you'll need to declare what the valid values of col can be,<p><pre><code> from sql_tstring import sql_context
with sql_context(columns="x"):
query, values = sql(t"SELECT {col} FROM y")
assert query == "SELECT x FROM y"
assert values == []
</code></pre>
Thus allowing you to protect against SQL injection.<p>As t-strings are format strings you can safely format the literals you'd like to pass as variables,<p><pre><code> text = "world"
query, values = sql(t"SELECT x FROM y WHERE x LIKE '%{text}'")
assert query == "SELECT x FROM y WHERE x LIKE ?"
assert values == ["%world"]
</code></pre>
This is especially useful when used with the Absent rewriting value.<p>SQL-tString is a SQL builder and as such you can use special RewritingValues to alter and build the query you want at runtime. This is best shown by considering a query you sometimes want to search by one column a, sometimes by b, and sometimes both,<p><pre><code> def search(
*,
a: str | AbsentType = Absent,
b: str | AbsentType = Absent
) -> tuple[str, list[str]]:
return sql(t"SELECT x FROM y WHERE a = {a} AND b = {b}")
assert search() == "SELECT x FROM y", []
assert search(a="hello") == "SELECT x FROM y WHERE a = ?", ["hello"]
assert search(b="world") == "SELECT x FROM y WHERE b = ?", ["world"]
assert search(a="hello", b="world") == (
"SELECT x FROM y WHERE a = ? AND b = ?", ["hello", "world"]
)
</code></pre>
Specifically Absent (which is an alias of RewritingValue.ABSENT) will remove the expression it is present in, and if there an no expressions left after the removal it will also remove the clause.<p>The other rewriting values I've included are handle the frustrating case of comparing to NULL, for example the following is valid but won't work as you'd likely expect,<p><pre><code> optional = None
sql(t"SELECT x FROM y WHERE x = {optional}")
</code></pre>
Instead you can use IsNull to achieve the right result,<p><pre><code> from sql_tstring import IsNull
optional = IsNull
query, values = sql(t"SELECT x FROM y WHERE x = {optional}")
assert query == "SELECT x FROM y WHERE x IS NULL"
assert values == []
</code></pre>
There is also a IsNotNull for the negated comparison.<p>The final feature allows for complex query building by nesting a t-string within the existing,<p><pre><code> inner = t"x = 'a'"
query, _ = sql(t"SELECT x FROM y WHERE {inner}")
assert query == "SELECT x FROM y WHERE x = 'a'"
</code></pre>
This library can be used today without Python3.14's t-strings with some limitations, <a href="https://github.com/pgjones/sql-tstring?tab=readme-ov-file#pre-python-314-usage">https://github.com/pgjones/sql-tstring?tab=readme-ov-file#pr...</a>, and I've been doing so this year. Thoughts and feedback very welcome.
Show HN: Easel – Code multiplayer games like singleplayer
For the past 3 years, I've been creating a new 2D game programming language where the multiplayer is completely automatic.
The idea is that someone who doesn't even know what a "remote procedure call" is can make a multiplayer game by just setting `maxHumanPlayers=5` and it "just works". The trick is the whole game simulation, including all the concurrent threads, can be executed deterministically and snapshotted for rollback netcode.<p>Normally when coding multiplayer you have to worry about following "the rules of multiplayer" like avoiding non-determinism, or not modifying entities your client has no authority over, but all that is just way too hard for someone who just wants to get straight into making games. So my idea was that if we put multiplayer into the fabric of the programming language, below all of your code, we can make the entire language multiplayer-safe. In Easel the entire world is hermetically sealed - there is nothing you can do to break multiplayer, which means it suits someone who just wants to make games and not learn all about networking. I've had people make multiplayer games on their first day of coding with Easel because you basically cannot go wrong.<p>There were so many other interesting things that went into this project. It's written in Rust and compiled to WebAssembly because I think that the zero-download nature of the web is a better way of getting many people together into multiplayer games. The networking is done by relaying peer-to-peer connections through Cloudflare Calls, which means Cloudflare collates the messages and reduces the bandwidth requirements for the clients so games can have more players.<p>I also took inspiration from my experience React when creating this language, here's how you would make a ship change color from green to red as it loses health:<p>`with Health {
ImageSprite(@ship.svg, color=(Health / MaxHealth).BlendHue(#ff6600, #66ff00))
}`<p>There is a lot of hidden magic that makes the code snippet above work - it creates a async coroutine that loops each time Health sends a signal, and the ImageSprite has an implicit ID assigned by the compiler so it knows which one to update each time around the loop. All of this lets you work at a higher level of abstraction and, in my opinion, make code that is easier to understand.<p>Speaking of async coroutines, my belief is that they don't get used enough in other game engines because their lifetimes are not tied to anything - you have this danger where they can outlive their entities and crash your game. In Easel each async task lives and dies with its entity, which is why we call them behaviors. Clear lifetime semantics makes it safe to use async tasks everywhere in Easel, which is why Easel games often consist of thousands of concurrently-executing behaviors. In my opinion, this untangles your code and makes it easier to understand.<p>That's just the beginning, there is even more to talk about, it has been a long journey these past 3 years, but I will stop there for now! I hope that, even for those people who don't care about the multiplayer capabilities of Easel, they just find it an interesting proposal of how a next-generation game programming language could work.<p>The Editor runs in your web browser and is free to play around with, so I would love to see more people try out making some games! Click the "Try it out" button to open the Sample Project and see if you can change the code to achieve the suggested tasks listed in the README.
Show HN: Easel – Code multiplayer games like singleplayer
For the past 3 years, I've been creating a new 2D game programming language where the multiplayer is completely automatic.
The idea is that someone who doesn't even know what a "remote procedure call" is can make a multiplayer game by just setting `maxHumanPlayers=5` and it "just works". The trick is the whole game simulation, including all the concurrent threads, can be executed deterministically and snapshotted for rollback netcode.<p>Normally when coding multiplayer you have to worry about following "the rules of multiplayer" like avoiding non-determinism, or not modifying entities your client has no authority over, but all that is just way too hard for someone who just wants to get straight into making games. So my idea was that if we put multiplayer into the fabric of the programming language, below all of your code, we can make the entire language multiplayer-safe. In Easel the entire world is hermetically sealed - there is nothing you can do to break multiplayer, which means it suits someone who just wants to make games and not learn all about networking. I've had people make multiplayer games on their first day of coding with Easel because you basically cannot go wrong.<p>There were so many other interesting things that went into this project. It's written in Rust and compiled to WebAssembly because I think that the zero-download nature of the web is a better way of getting many people together into multiplayer games. The networking is done by relaying peer-to-peer connections through Cloudflare Calls, which means Cloudflare collates the messages and reduces the bandwidth requirements for the clients so games can have more players.<p>I also took inspiration from my experience React when creating this language, here's how you would make a ship change color from green to red as it loses health:<p>`with Health {
ImageSprite(@ship.svg, color=(Health / MaxHealth).BlendHue(#ff6600, #66ff00))
}`<p>There is a lot of hidden magic that makes the code snippet above work - it creates a async coroutine that loops each time Health sends a signal, and the ImageSprite has an implicit ID assigned by the compiler so it knows which one to update each time around the loop. All of this lets you work at a higher level of abstraction and, in my opinion, make code that is easier to understand.<p>Speaking of async coroutines, my belief is that they don't get used enough in other game engines because their lifetimes are not tied to anything - you have this danger where they can outlive their entities and crash your game. In Easel each async task lives and dies with its entity, which is why we call them behaviors. Clear lifetime semantics makes it safe to use async tasks everywhere in Easel, which is why Easel games often consist of thousands of concurrently-executing behaviors. In my opinion, this untangles your code and makes it easier to understand.<p>That's just the beginning, there is even more to talk about, it has been a long journey these past 3 years, but I will stop there for now! I hope that, even for those people who don't care about the multiplayer capabilities of Easel, they just find it an interesting proposal of how a next-generation game programming language could work.<p>The Editor runs in your web browser and is free to play around with, so I would love to see more people try out making some games! Click the "Try it out" button to open the Sample Project and see if you can change the code to achieve the suggested tasks listed in the README.
Show HN: KVSplit – Run 2-3x longer contexts on Apple Silicon
I discovered that in LLM inference, keys and values in the KV cache have very different quantization sensitivities. Keys need higher precision than values to maintain quality.<p>I patched llama.cpp to enable different bit-widths for keys vs. values on Apple Silicon. The results are surprising:<p>- K8V4 (8-bit keys, 4-bit values): 59% memory reduction with only 0.86% perplexity loss
- K4V8 (4-bit keys, 8-bit values): 59% memory reduction but 6.06% perplexity loss
- The configurations use the same number of bits, but K8V4 is 7× better for quality<p>This means you can run LLMs with 2-3× longer context on the same Mac. Memory usage scales with sequence length, so savings compound as context grows.<p>Implementation was straightforward:
1. Added --kvq-key and --kvq-val flags to llama.cpp
2. Applied existing quantization logic separately to K and V tensors
3. Validated with perplexity metrics across context lengths
4. Used Metal for acceleration (with -mlong-calls flag to avoid vectorization issues)<p>Benchmarked on an M4 MacBook Pro running TinyLlama with 8K context windows. Compatible with Metal/MPS and optimized for Apple Silicon.<p>GitHub: <a href="https://github.com/dipampaul17/KVSplit">https://github.com/dipampaul17/KVSplit</a>
Show HN: KVSplit – Run 2-3x longer contexts on Apple Silicon
I discovered that in LLM inference, keys and values in the KV cache have very different quantization sensitivities. Keys need higher precision than values to maintain quality.<p>I patched llama.cpp to enable different bit-widths for keys vs. values on Apple Silicon. The results are surprising:<p>- K8V4 (8-bit keys, 4-bit values): 59% memory reduction with only 0.86% perplexity loss
- K4V8 (4-bit keys, 8-bit values): 59% memory reduction but 6.06% perplexity loss
- The configurations use the same number of bits, but K8V4 is 7× better for quality<p>This means you can run LLMs with 2-3× longer context on the same Mac. Memory usage scales with sequence length, so savings compound as context grows.<p>Implementation was straightforward:
1. Added --kvq-key and --kvq-val flags to llama.cpp
2. Applied existing quantization logic separately to K and V tensors
3. Validated with perplexity metrics across context lengths
4. Used Metal for acceleration (with -mlong-calls flag to avoid vectorization issues)<p>Benchmarked on an M4 MacBook Pro running TinyLlama with 8K context windows. Compatible with Metal/MPS and optimized for Apple Silicon.<p>GitHub: <a href="https://github.com/dipampaul17/KVSplit">https://github.com/dipampaul17/KVSplit</a>
Show HN: Visual flow-based programming for Erlang, inspired by Node-RED
Hi There,<p>Erlang-RED has been my project for the last couple of months and I would love to get some feedback from the HN community.<p>The idea is to take advantage of Erlangs message passing and low overhead processes to have true concurrency in Node-RED flows. Plus also to bring low-code visual flow-based programming to Erlang.
Show HN: Visual flow-based programming for Erlang, inspired by Node-RED
Hi There,<p>Erlang-RED has been my project for the last couple of months and I would love to get some feedback from the HN community.<p>The idea is to take advantage of Erlangs message passing and low overhead processes to have true concurrency in Node-RED flows. Plus also to bring low-code visual flow-based programming to Erlang.
Show HN: Visual flow-based programming for Erlang, inspired by Node-RED
Hi There,<p>Erlang-RED has been my project for the last couple of months and I would love to get some feedback from the HN community.<p>The idea is to take advantage of Erlangs message passing and low overhead processes to have true concurrency in Node-RED flows. Plus also to bring low-code visual flow-based programming to Erlang.
Show HN: Real-Time Gaussian Splatting
LiveSplat is a system for turning RGBD camera streams into Gaussian splat scenes in real-time. The system works by passing all the RGBD frames into a feed forward neural net that outputs the current scene as Gaussian splats. These splats are then rendered in real-time. I've put together a demo video at the link above.
Show HN: Real-Time Gaussian Splatting
LiveSplat is a system for turning RGBD camera streams into Gaussian splat scenes in real-time. The system works by passing all the RGBD frames into a feed forward neural net that outputs the current scene as Gaussian splats. These splats are then rendered in real-time. I've put together a demo video at the link above.
Show HN: Real-Time Gaussian Splatting
LiveSplat is a system for turning RGBD camera streams into Gaussian splat scenes in real-time. The system works by passing all the RGBD frames into a feed forward neural net that outputs the current scene as Gaussian splats. These splats are then rendered in real-time. I've put together a demo video at the link above.
Show HN: Undetectag, track stolen items with AirTag
I developed a device that turns an Airtag on and off at specific intervals.
Current Airtags are detectable right away and cannot be used to track stolen property. That device allows you to hide an Airtag in your car, for example, and someone that steals your car will not be able to use some app to detect it.
The Airtag will also not warn the thief of its presence. After some hours, the Airtag turns on again and you can find out its location. It’s not foolproof, as the timing has to be right, but still useful.<p>What do you think?
Show HN: Undetectag, track stolen items with AirTag
I developed a device that turns an Airtag on and off at specific intervals.
Current Airtags are detectable right away and cannot be used to track stolen property. That device allows you to hide an Airtag in your car, for example, and someone that steals your car will not be able to use some app to detect it.
The Airtag will also not warn the thief of its presence. After some hours, the Airtag turns on again and you can find out its location. It’s not foolproof, as the timing has to be right, but still useful.<p>What do you think?
Show HN: Min.js style compression of tech docs for LLM context
Show HN: Min.js style compression of tech docs for LLM context
Show HN: I’ve built an IoT device to let my family know when I’m in a meeting