website

Portfolio website
git clone https://willem.vanzwol.com/git/website/repo.bundle
Log | Files | Refs | README | LICENSE

commit a0ec3e1236bf15f75b39831c8792d0952b25be92
parent 7ed22017370127aec8a92413ddd880eec7d24724
Author: Willem Van Zwol <willem@vanzwol.com>
Date:   Mon,  1 Jun 2026 16:26:13 -0700

Updated some styling and added blog post

Diffstat:
Mblog.html | 53++++++++++++++++++++++++++++++++++++++++-------------
Ablogs/jxl_and_compression_on_nix.html | 427+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablogs/librenet.html | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mindex.html | 25-------------------------
Mrss.xml | 13++++++++++++-
Mstyles.css | 91++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
6 files changed, 679 insertions(+), 49 deletions(-)

diff --git a/blog.html b/blog.html @@ -13,9 +13,9 @@ <!-- LEFT --> <div class="nav-left"> <a href="./index.html">index</a> ~ - <a href="./blog.html">blog</a> ~ - <a href="./projects.html">projects</a> ~ - <a href="./contact.html">contact</a> + <a href="">blog</a> ~ + <a href="">projects</a> ~ + <a href="">contact</a> </div> <!-- CENTER --> <div class="nav-center"> @@ -50,22 +50,49 @@ </div> </nav> <h1>Blog posts</h1> + <a href="./rss.xml"> + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 -1 32 32" + fill="currentColor" + width="0.8em" + height="0.8em" + aria-hidden="true" + > + <path d="M20.885 30.996h-5.83c-0.037-7.745-6.306-14.014-14.047-14.052h-0.004v-5.83c10.958 0.055 19.826 8.924 19.881 19.877l0 0.005zM5.117 22.767c0.001 0 0.001 0 0.002 0 2.272 0 4.114 1.842 4.114 4.114s-1.842 4.114-4.114 4.114c-2.271 0-4.113-1.84-4.114-4.111v-0c0.003-2.271 1.842-4.112 4.112-4.118h0.001zM24.996 30.996c-0.064-13.225-10.767-23.928-23.986-23.993l-0.006-0v-5.998c16.531 0.082 29.91 13.461 29.991 29.984l0 0.008z" /> + </svg> RSS Feed</a> + <button style="margin-left: 1ch" onclick="navigator.clipboard.writeText('willem.vanzwol.com/rss.xml')"> + Copy + </button> + <br> + Filtering is not yet supported, files are listed in order of date.<br><br> + + <a class="tile" href="./blogs/jxl_and_compression_on_nix.html"> + <fieldset> + <span>scripting • compression • nix</span> + <h2>JXL and Compression on nix</h2> + <div>2026.00.01</div> + Showcase of a script and flake I made for compressing JPG/JEPG to JXL and compressing into a tarball or .7z file<br> + </fieldset> + </a> <a class="tile" href="./blogs/on_the_blog.html"> <fieldset> - <span>website ~ blog ~ complexity</span> - <h2>On the blog</h2> - <div>2026.05.21</div> - Post about my thoughts on how the blog should work.<br> - </fieldset></a> + <span>website • blog • complexity</span> + <h2>On the Blog</h2> + <div>2026.05.21</div> + Post about my thoughts on how the blog should work.<br> + </fieldset> + </a> <a class="tile" href="./blogs/website.html"> <fieldset> - <span>website</span> - <h2>Website</h2> - <div>2026.05.19</div> - Overview of the point of this website.<br> - </fieldset></a> + <span>website</span> + <h2>Website</h2> + <div>2026.05.21</div> + Overview of the point of this website.<br> + </fieldset> + </a> </body> </html> diff --git a/blogs/jxl_and_compression_on_nix.html b/blogs/jxl_and_compression_on_nix.html @@ -0,0 +1,427 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Portfolio</title> + <link rel="icon" type="image/x-icon" href="../favicon.ico"> + <link rel="stylesheet" type="text/css" href="../styles.css"> + <script src="../script.js"></script> +</head> +<body> +<nav> + <!-- LEFT --> + <div class="nav-left"> + <a href="../index.html">index</a> ~ + <a href="../blog.html">blog</a> ~ + <a href="../projects.html">projects</a> ~ + <a href="../contact.html">contact</a> + </div> + <!-- CENTER --> + <div class="nav-center"> + </div> + <!-- RIGHT --> + <div class="nav-right"> + <a href="../git/website/log.html" + title="Self hosted repo of this website"> + + <!-- giticon --> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" + style="width: 0.85em; position: relative; top: 0.06em; + fill:var(--text)"> + <path d="M15,5.6,10.4,1A3.4,3.4,0,0,0,5.78.86L7.66,2.74a1.25, + 1.25,0,0,1,1.67,1.2V4a1.23,1.23,0,0,1-.08.38l2.45, + 2.4a1.17,1.17,0,0,1,.37-.08A1.3,1.3,0,1,1,10.77, + 8h0a1.17,1.17,0,0,1,.08-.37L8.6,5.38v5.23a1.28,1.28,0, + 0,1,.73,1.15,1.3,1.3,0,0,1-2.6,0,1.27,1.27,0,0,1, + .67-1.11V5.07A1.27,1.27,0,0,1,6.73,4a1.17,1.17,0,0,1, + .08-.37l-1.9-1.9L1,5.6a3.38,3.38,0,0,0,0,4.79H1L5.6, + 15a3.38,3.38,0,0,0,4.79,0h0L15,10.4a3.38,3.38,0,0,0, + 0-4.79Z"/> + </svg> + </a> + <input type="checkbox" id="theme-toggle" class="toggle"> + <label for="theme-toggle" class="btn" + title="Light/Dark mode (JS required)"> + + <!-- sun --> + <svg class="sun" viewBox="0 0 24 24" fill=none + stroke=currentColor stroke-linecap=round + stroke-width="1.8"> + <circle cx=12 cy=12 r=4.4 /> + <path d="M12 2v3m0 14v3M2 12h3m14 0h3M5 5l2 2m10 10l2 + 2M5 19l2-2m10-10l2-2"/> + </svg> + + <!-- moon --> + <svg class="moon" viewBox="0 0 24 24"> + <path d="M21 12.8A9 9 0 0 1 9 3c0-.3 0-.7.1-1A10 10 0 1 + 0 23 12.4c-.3 0-.7.1-1 .1z"/> + + </svg> + </label> + </div> +</nav> + +<h1>JXL and Compression on Nix</h1> +2026.05.29<br><br> + +I recently made a backup of photos +I've been taking over the last few years on a Fujifilm x100 (2010). +And I wanted to find the best format and way to compress it.<br><br> + +This can act as both a guide and a blog if I've written it well enough, +so you can compress images on nixos (or linux) yourself. + +<h2>Why JXL?</h2> +For this process, +I will not just be making a <code>.zip</code> or <code>.tar.gz</code> +I also will be converting the JPG/JPEG files, +and will do so with <code>.jxl</code>.<br><br> + +I believe that <abbr +title="JPG/JPEG XL Image Coding System, supporting both lossy and lossless"> + <code>.jxl</code></abbr> is an incredible format, +and it's really too bad <a +href="https://groups.google.com/a/chromium.org/g/blink-dev/c/WjCKcBw219k/m/Ocsmn8NHAwAJ" + >Google is yet to support it in chrome</a> +despite <details><summary>high demand</summary> + + <aside class="left"> +<blockquote + cite="https://en.wikipedia.org/wiki/JPEG_XL#Industry_support_and_adoption"> +various representatives of well-known industry brand names +have publicly voiced support for JPEG XL +as their preferred choice, +including Facebook, Adobe, Intel, ... + +<a class="quote-source" + href="https://en.wikipedia.org/wiki/JPEG_XL#Industry_support_and_adoption" + aria-label="Source" + ></a> +</blockquote> +According to Wikipedia<br><br> + +The list contines on a lot longer. +For this reason Google's abilivalent stance on supporting it in Chrome +resulted in a lot of pushback from the community. + </aside> +</details> + +. +Google had instead pushed for <a + href="https://lobste.rs/s/27hc2m/google_explains_why_it_s_removing_jpeg_xl"> + AVIF a competitor to JXL</a> +which in my opinion is inferior. +<abbr title="The video codec that AVIF is derived from">AV1</abbr> however, +is incredible! +and I am patiently awaitng the release of AV2 +and it's adoption.<br><br> + +JXL in particular is built around JPEG interoperability, +so converting files from JPEG to JXL can preserve visual quality +while significantly reducing file size. +But most importantly It also supports <abbr title= +"decodes in multiple passes, a low quality image that refines displays faster"> + Progressive loading</abbr>.<br><br> + +Years later, +and google <a href="https://www.phoronix.com/news/Chrome-145-Released"> + may support it</a> very soon! +Firefox is likely to follow suit, +and safari already does, along with a bunch of software like +<a href="https://www.gimp.org/">Gimp</a>, +<a href="https://krita.org/">Krita</a> and Photoshop do. +Hopefully I am not just being overly optimistic, +because I do believe that JXL is the future. + +<h2>JXL compression</h2> +Firstly, you need <code>libjxl</code> installed. +On nixos this is easy to do in a shell: +<pre data-lang="bash"> +nix-shell -p libjxl +</pre> +<aside class="left"> + You can click code blocks to copy there contents to clipboard! +</aside> +<pre data-lang="bash"> +cjxl input.jpg output.jxl +</pre> +<div class="callout note"> + Installing packages like <code>libjxl</code> depends on package manager, + nearly all unix systems can <a href="https://nixos.org/download/"> + install nix though</a> + (and i'd recommend it). +</div> + +The command above may be all you need depending on your use case. +For me I want a short script to automate this. + +<h2>Automate it!</h2> + +I've been +<details> + <summary>wanting to learn</summary> + <aside class="left"> +Because I am using nix, +it enables is for the reliablity and quality of your code to matter more +than accessability of language. +Normally I would just use bash so it's easy to run, +but as I mention nushell catches more errors before runtime. + </aside> +</details> +<a href="https://www.nushell.sh/"> + nushell</a> for scripting, +and I don't regret it one bit. +It has structured data, +<abbr title="Nu speaks JSON, YAML, SQLite, Excel, and more out of the box"> + batteries included</abbr> +and <em>rust like errors</em>. +In my experience languages with great error messages +(and a cult following) +are +<details> + <summary>all amazing.</summary> +<aside class="right"> + Afterall, if a language doesn't have good compiler output + it's <abbr title= +"Protocol that per langage gives inline errors and autocomplete in your editor" + >LSP</abbr> is going to be terrible too. + + It's a good reason to avoid interpreted languages and C + unless it's very well suited for your use case + and you are willing to learn it well to do it well. +</aside> +</details> +<br><br> + +In my case the DCIM folder has multiple folders inside that has the JPEGS, +so I want to recursively go through every file +and recreate the same file tree in a new directory +for the compressed files.<br><br> + +Here is the script (<code>./compress.nu</code>) + I ended up making and how to use it. + +<!-- HTML generated using hilite.me --><pre id="compress.nu" data-lang="nu"><span></span><span style="color: #56B6C2">#</span><span style="color: #E06C75">!/usr/bin/env</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">nu</span> +<span style="color: #56B6C2">#</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">compress.nu</span> + +<span style="color: #C678DD">def </span><span style="color: #E06C75">main</span><span style="color: #ABB2BF"> [</span><span style="color: #E06C75">out_dir</span><span style="color: #ABB2BF">: </span><span style="color: #E06C75">path</span><span style="color: #ABB2BF">] {</span> + +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">mkdir</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">$out_dir</span> + +<span style="color: #ABB2BF"> </span><span style="color: #C678DD">let </span><span style="color: #E06C75">files</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">= </span><span style="color: #ABB2BF">(</span> +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">ls</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">**/*</span><span style="color: #ABB2BF"> </span> +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">where</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">type</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">== </span><span style="color: #E06C75">file</span> +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">where</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">name </span><span style="color: #E06C75">=</span><span style="color: #56B6C2">~</span><span style="color: #ABB2BF"> </span><span style="color: #56B6C2">&#39;</span><span style="color: #ABB2BF">(</span><span style="color: #61AFEF; font-weight: bold">?i</span><span style="color: #ABB2BF">)</span><span style="color: #98C379">\.</span><span style="color: #ABB2BF">(</span><span style="color: #61AFEF; font-weight: bold">jpg|jpeg</span><span style="color: #ABB2BF">)</span><span style="color: #E06C75">$</span><span style="color: #56B6C2">&#39;</span> +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">get </span><span style="color: #E06C75">name</span> +<span style="color: #ABB2BF"> )</span> + +<span style="color: #ABB2BF"> </span><span style="color: #C678DD">if </span><span style="color: #ABB2BF">(</span><span style="color: #61AFEF; font-weight: bold">$files</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">is-empty</span><span style="color: #ABB2BF">) {</span> +<span style="color: #ABB2BF"> </span><span style="color: #E5C07B">print </span><span style="color: #98C379">&quot;No jpg/jpeg files found&quot;</span> +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">exit</span><span style="color: #ABB2BF"> </span><span style="color: #D19A66">1</span> +<span style="color: #ABB2BF"> }</span> + +<span style="color: #ABB2BF"> </span><span style="color: #E5C07B">for </span><span style="color: #E06C75">f</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">in</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">$files</span><span style="color: #ABB2BF"> {</span> +<span style="color: #ABB2BF"> </span><span style="color: #C678DD">let </span><span style="color: #E06C75">base</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">= </span><span style="color: #ABB2BF">(</span><span style="color: #61AFEF; font-weight: bold">$f</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">path parse </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">reject</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">extension</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">path </span><span style="color: #E06C75">join</span><span style="color: #ABB2BF">)</span> +<span style="color: #ABB2BF"> </span><span style="color: #C678DD">let </span><span style="color: #E06C75">out</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">= </span><span style="color: #ABB2BF">(</span><span style="color: #61AFEF; font-weight: bold">$out_dir</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">path join </span><span style="color: #ABB2BF">(</span><span style="color: #61AFEF; font-weight: bold">$base</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">+ </span><span style="color: #98C379">&quot;.jxl&quot;</span><span style="color: #ABB2BF">))</span> + +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">mkdir</span><span style="color: #ABB2BF"> (</span><span style="color: #61AFEF; font-weight: bold">$out</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">path </span><span style="color: #E06C75">dirname</span><span style="color: #ABB2BF">)</span> + +<span style="color: #ABB2BF"> </span><span style="color: #C678DD">if </span><span style="color: #ABB2BF">(</span><span style="color: #61AFEF; font-weight: bold">$out</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">|</span><span style="color: #ABB2BF"> </span><span style="color: #E5C07B">path </span><span style="color: #E06C75">exists</span><span style="color: #ABB2BF">) {</span> +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">continue</span> +<span style="color: #ABB2BF"> }</span> + +<span style="color: #ABB2BF"> </span><span style="color: #E5C07B">print </span><span style="color: #E06C75">$</span><span style="color: #98C379">&quot;Converting: ($f) -&gt; ($out)&quot;</span> +<span style="color: #ABB2BF"> </span><span style="color: #E06C75">cjxl</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">$f</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">$out</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">-d</span><span style="color: #ABB2BF"> </span><span style="color: #D19A66">2</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">-e</span><span style="color: #ABB2BF"> </span><span style="color: #D19A66">9</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75">--lossless_jpeg=0</span> +<span style="color: #ABB2BF"> }</span> +<span style="color: #ABB2BF">}</span> +</pre> +<div class="callout note"> + That last line does a lot of the heavy lifting. + Right now it’s set to maximum effort (9) and lossy output (0). + Lower the 9 to reduce effort (e.g. 3). + Flip the last 0 to 1 to enable lossless, + also then remove <code>-d 2 </code> segment. +</div> + +<pre data-lang="bash"> +nix-shell -p nushell libjxl +</pre> +<pre data-lang="bash"> +nu compress.nu out_dir/ +</pre> + +This will work recursively into all sub directories of where the script is +executed. +It will also ignore all non JPG/JPEG files. +So if you have other file formats as well mixed in (like I do <code>RAF</code>) +then you need to convert that too. +But you need not do it first, +because this script will detect what files have already been done and not redo. + +<h2>Tarball compression</h2> +Lastly compressing everything with a tarball. +Zip works fine, + +<pre data-lang="bash"> +nix-shell -p zip +zip -r archive.zip myfolder +</pre> + +and in practice you should proabbly do both, +but tar balls work better for lots of files. +Zip losslessly compresses on a file-per-file basis +and wouldn't actually help that much here +given each file is already so efficiently compressed. +Earlier I mentioned <code>.tar.gz</code> +which is generated via <code>gzip</code> on a <code>.tar</code>, +but there are more efficient compression algorithms but run for longer +and use more power. +<br><br> + +<details> + <summary>There are lots of options</summary> +These are in increasing order of least to most compute time for smaller results. +<pre data-lang="bash"> +tar -cf - dir/ | gzip -9 -n > archive.tar.gz</pre> +<pre data-lang="bash"> +tar -cf - dir/ | bzip2 -9 > archive.tar.bz2</pre> +<pre data-lang="bash"> +tar -cf - dir/ | xz -9 -e -T0 > archive.tar.xz</pre> +<pre data-lang="bash"> +tar -cf - dir/ | zstd -22 -T0 --ultra -o archive.tar.zst</pre> +<pre data-lang="bash"> +7z a -t7z -mx=9 -m0=lzma2 -mmt=on archive.7z dir/</pre> +</details>.<br> + +I was planning on trying each and have it run overnight, +but this part of the process ended up being a so much quicker than I expected. +<br><br><hr><br> +Using <code>p7zip</code> here were the final results.<br> +I compressed 14.1 GB of photos down to 1.8 GB (lossy), and 9.2 GB (lossless). + <br> +Only using p7zip without JXL then only compresses to 13.3 GB, +so JXL ened up being well worth it. + +<h2>Nix flake stuff</h2> +Especially if you don't use nix, +then you can stop reading here. +The script most likely worked fine. +Eventually I will make another blog post about why I bother with nix.<br><br> + +Either way, here are two methods for running nushell via nix. +One solution is you run it inline like this: +<!-- HTML generated using hilite.me --><pre data-lang="nix" ><span></span><span style="color: #E6EDF3">{</span> + inputs<span style="color: #FF7B72; font-weight: bold">.</span>nixpkgs<span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">url</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;github:NixOS/nixpkgs/nixos-unstable&quot;</span><span style="color: #E6EDF3">;</span> + + <span style="color: #A5D6FF">outputs</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #E6EDF3">{</span> self<span style="color: #E6EDF3">,</span> nixpkgs <span style="color: #E6EDF3">}:</span> + <span style="color: #FF7B72">let</span> + <span style="color: #A5D6FF">system</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;x86_64-linux&quot;</span><span style="color: #E6EDF3">;</span> + <span style="color: #A5D6FF">pkgs</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #E6EDF3">import</span> nixpkgs <span style="color: #E6EDF3">{</span> <span style="color: #FF7B72">inherit</span> system<span style="color: #E6EDF3">;</span> <span style="color: #E6EDF3">};</span> + + <span style="color: #A5D6FF">app</span> <span style="color: #FF7B72; font-weight: bold">=</span> pkgs<span style="color: #FF7B72; font-weight: bold">.</span>writeShellScriptBin <span style="color: #A5D6FF">&quot;run-nu&quot;</span> <span style="color: #A5D6FF">&#39;&#39;</span> +<span style="color: #A5D6FF"> exec ${</span>pkgs<span style="color: #FF7B72; font-weight: bold">.</span>nushell<span style="color: #A5D6FF">}/bin/nu ${</span>pkgs<span style="color: #FF7B72; font-weight: bold">.</span>writeText <span style="color: #A5D6FF">&quot;hello.nu&quot;</span> <span style="color: #A5D6FF">&#39;&#39;</span> +<span style="color: #A5D6FF">def main [out_dir: path] {</span> + +<span style="color: #A5D6FF"> mkdir $out_dir</span> + +<span style="color: #A5D6FF"> let files = (</span> +<span style="color: #A5D6FF"> ls **/* </span> +<span style="color: #A5D6FF"> | where type == file</span> +<span style="color: #A5D6FF"> | where name =~ &#39;(?i)\.(jpg|jpeg)$&#39;</span> +<span style="color: #A5D6FF"> | get name</span> +<span style="color: #A5D6FF"> )</span> + +<span style="color: #A5D6FF"> if ($files | is-empty) {</span> +<span style="color: #A5D6FF"> print &quot;No jpg/jpeg files found&quot;</span> +<span style="color: #A5D6FF"> exit 1</span> +<span style="color: #A5D6FF"> }</span> + +<span style="color: #A5D6FF"> for f in $files {</span> +<span style="color: #A5D6FF"> let base = ($f | path parse | reject extension | path join)</span> +<span style="color: #A5D6FF"> let out = ($out_dir | path join ($base + &quot;.jxl&quot;))</span> + +<span style="color: #A5D6FF"> mkdir ($out | path dirname)</span> + +<span style="color: #A5D6FF"> if ($out | path exists) {</span> +<span style="color: #A5D6FF"> continue</span> +<span style="color: #A5D6FF"> }</span> + +<span style="color: #A5D6FF"> print $&quot;Converting: ($f) -&gt; ($out)&quot;</span> +<span style="color: #A5D6FF"> ${pkgs.cjxl} $f $out -d 2 -e 9 --lossless_jpeg=0</span> +<span style="color: #A5D6FF"> }</span> +<span style="color: #A5D6FF">}</span> + +<span style="color: #A5D6FF"> &#39;&#39;}</span> +<span style="color: #A5D6FF"> &#39;&#39;</span><span style="color: #E6EDF3">;</span> + <span style="color: #FF7B72">in</span> <span style="color: #E6EDF3">{</span> + apps<span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">${</span>system<span style="color: #A5D6FF">}</span><span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">default</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #E6EDF3">{</span> + <span style="color: #A5D6FF">type</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;app&quot;</span><span style="color: #E6EDF3">;</span> + <span style="color: #A5D6FF">program</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;${</span>app<span style="color: #A5D6FF">}/bin/run-nu&quot;</span><span style="color: #E6EDF3">;</span> + <span style="color: #E6EDF3">};</span> + <span style="color: #E6EDF3">};</span> +<span style="color: #E6EDF3">}</span> +</pre> +<pre data-lang="bash"> +nix runs -- ./path/to/dir +</pre> + +The other solution is to put the nushell script in another file and link to it +<code>(./scipt.nu)</code>. +This is best if you want to modify and debug things, +as you get actual syntax highlighting, <abbr title= +"Protocol that per langage gives inline errors and autocomplete in your editor" + >LSP</abbr> +and better erros running it from the dev shell.<br><br> +The script is the <a href="#compress.nu">same one above</a>. + +<!-- HTML generated using hilite.me --><pre data-lang="nix" ><span></span><span style="color: #E6EDF3">{</span> + inputs<span style="color: #FF7B72; font-weight: bold">.</span>nixpkgs<span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">url</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;github:NixOS/nixpkgs/nixos-unstable&quot;</span><span style="color: #E6EDF3">;</span> + + <span style="color: #A5D6FF">outputs</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #E6EDF3">{</span> self<span style="color: #E6EDF3">,</span> nixpkgs <span style="color: #E6EDF3">}:</span> <span style="color: #FF7B72">let</span> + <span style="color: #A5D6FF">system</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;x86_64-linux&quot;</span><span style="color: #E6EDF3">;</span> + <span style="color: #A5D6FF">pkgs</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #E6EDF3">import</span> nixpkgs <span style="color: #E6EDF3">{</span> <span style="color: #FF7B72">inherit</span> system<span style="color: #E6EDF3">;</span> <span style="color: #E6EDF3">};</span> + + <span style="color: #A5D6FF">app</span> <span style="color: #FF7B72; font-weight: bold">=</span> pkgs<span style="color: #FF7B72; font-weight: bold">.</span>writeShellApplication <span style="color: #E6EDF3">{</span> + <span style="color: #A5D6FF">name</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;run-nu&quot;</span><span style="color: #E6EDF3">;</span> + <span style="color: #A5D6FF">runtimeInputs</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #FF7B72">with</span> pkgs<span style="color: #E6EDF3">;</span> <span style="color: #E6EDF3">[</span> nushell libjxl <span style="color: #E6EDF3">];</span> + <span style="color: #A5D6FF">text</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&#39;&#39;</span> +<span style="color: #A5D6FF"> exec nu ${./script.nu} &quot;$@&quot;</span> +<span style="color: #A5D6FF"> &#39;&#39;</span><span style="color: #E6EDF3">;</span> + <span style="color: #E6EDF3">};</span> + <span style="color: #FF7B72">in</span> <span style="color: #E6EDF3">{</span> + apps<span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">${</span>system<span style="color: #A5D6FF">}</span><span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">default</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #E6EDF3">{</span> + <span style="color: #A5D6FF">type</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;app&quot;</span><span style="color: #E6EDF3">;</span> + <span style="color: #A5D6FF">program</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #A5D6FF">&quot;${</span>app<span style="color: #A5D6FF">}/bin/run-nu&quot;</span><span style="color: #E6EDF3">;</span> + <span style="color: #E6EDF3">};</span> + + devShells<span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">${</span>system<span style="color: #A5D6FF">}</span><span style="color: #FF7B72; font-weight: bold">.</span><span style="color: #A5D6FF">default</span> <span style="color: #FF7B72; font-weight: bold">=</span> pkgs<span style="color: #FF7B72; font-weight: bold">.</span>mkShell <span style="color: #E6EDF3">{</span> + <span style="color: #A5D6FF">buildInputs</span> <span style="color: #FF7B72; font-weight: bold">=</span> <span style="color: #FF7B72">with</span> pkgs<span style="color: #E6EDF3">;</span> <span style="color: #E6EDF3">[</span> nushell libjxl <span style="color: #E6EDF3">];</span> + <span style="color: #E6EDF3">};</span> + <span style="color: #E6EDF3">}</span> +<span style="color: #E6EDF3">}</span> +</pre> + + +<div class="callout note"> +There is actually a simpler way to do this, +but this is better setup in case you want to use it in other places +or modify it.<br><br> +Essentially <code>libjxl</code> is included here in the runtime inputs, +because we aren't referring to packages as <code>pkgs.libjxl</code> for example, +we instead need to declare them before trying to run the script. +</div> +<pre data-lang="bash"> +nix develop +</pre> +<pre data-lang="bash"> +nu ./script.nu ./path/to/dir +</pre> +Or simply: +<pre data-lang="bash"> +nix runs -- ./path/to/dir +</pre> + +</body> +</html> diff --git a/blogs/librenet.html b/blogs/librenet.html @@ -0,0 +1,119 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Portfolio</title> + <link rel="icon" type="image/x-icon" href="../favicon.ico"> + <link rel="stylesheet" type="text/css" href="../styles.css"> + <script src="../script.js"></script> +</head> +<body> +<nav> + <!-- LEFT --> + <div class="nav-left"> + <a href="../index.html">index</a> ~ + <a href="../blog.html">blog</a> ~ + <a href="../projects.html">projects</a> ~ + <a href="../contact.html">contact</a> + </div> + <!-- CENTER --> + <div class="nav-center"> + </div> + <!-- RIGHT --> + <div class="nav-right"> + <a href="../git/website/log.html" + title="Self hosted repo of this website"> + + <!-- giticon --> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" + style="width: 0.85em; position: relative; top: 0.06em; + fill:var(--text)"> + <path d="M15,5.6,10.4,1A3.4,3.4,0,0,0,5.78.86L7.66,2.74a1.25, + 1.25,0,0,1,1.67,1.2V4a1.23,1.23,0,0,1-.08.38l2.45, + 2.4a1.17,1.17,0,0,1,.37-.08A1.3,1.3,0,1,1,10.77, + 8h0a1.17,1.17,0,0,1,.08-.37L8.6,5.38v5.23a1.28,1.28,0, + 0,1,.73,1.15,1.3,1.3,0,0,1-2.6,0,1.27,1.27,0,0,1, + .67-1.11V5.07A1.27,1.27,0,0,1,6.73,4a1.17,1.17,0,0,1, + .08-.37l-1.9-1.9L1,5.6a3.38,3.38,0,0,0,0,4.79H1L5.6, + 15a3.38,3.38,0,0,0,4.79,0h0L15,10.4a3.38,3.38,0,0,0, + 0-4.79Z"/> + </svg> + </a> + <input type="checkbox" id="theme-toggle" class="toggle"> + <label for="theme-toggle" class="btn" + title="Light/Dark mode (JS required)"> + + <!-- sun --> + <svg class="sun" viewBox="0 0 24 24" fill=none + stroke=currentColor stroke-linecap=round + stroke-width="1.8"> + <circle cx=12 cy=12 r=4.4 /> + <path d="M12 2v3m0 14v3M2 12h3m14 0h3M5 5l2 2m10 10l2 + 2M5 19l2-2m10-10l2-2"/> + </svg> + + <!-- moon --> + <svg class="moon" viewBox="0 0 24 24"> + <path d="M21 12.8A9 9 0 0 1 9 3c0-.3 0-.7.1-1A10 10 0 1 + 0 23 12.4c-.3 0-.7.1-1 .1z"/> + + </svg> + </label> + </div> +</nav> + +<h1>Librenet</h1> +2026.04.26 + +<p> +This concept is Massive. +I will most likely neeed to make multiple blog posts +to really cover the entirety of what Librenet would be. +That said, I do think I've found a consice enough way to talk about a +part of it that gets you to infer the other features I may want. +</p> + +<h2>A Network of Relays</h2> +<p> + +You have a collection of devices that all in a network +call them <em>nodes</em>. + +They all have IP addresses, +are listening on ports for TCP/UDP +and know the <code>IP:port</code> touples of every other node. + +The goal is for this network to act as a cloud for storage. +Each node also can represent a user +that wants files stored on this cloud.<br><br> + +<details> + <summary>erasure codes</summary> + <aside> + + A naive approach is a node selects a device at random to store a file for them + the node in question gets to just store a pointer to the device that has it. + + <br><br> + + Under imperfect uptime and trust that's fine. + But in reality you want some way to break up the file into pieces + such that you only need a fraction of those pieces to reconstruct the file. + + <br><br> + + This is called erasure codes + </aside> +</details> + +would be used eg. +<a href= + "https://www.cs.cmu.edu/~guyb/realworld/reedsolomon/reed_solomon_codes.html" + title="Block-based error correcting codes with a wide range of applications" + >Reed-Solomon +</a> + +</p> +</body> +</html> diff --git a/index.html b/index.html @@ -106,30 +106,5 @@ <a href="./git/website/log.html"> self hosted git</a>. </p> - <hr> - <p> - I have created the <code>styles.css</code> myself, - checkout the markdown emulated syntax!<br> - <em>italics</em>, <b>bold</b>, <del>strickthrough</del> - <blockquote cite="https://example.com"> - Software is like sex, it's better when it's free<br> - - Linus Torvalds - <a class="quote-source" - href="https://example.com" - aria-label="Source" - ></a> - </blockquote> - <ul><li>item</li> - <li>item</li></ul> - <ol><li>item</li> - <li>item</li></ol> - - <div class="callout note"> - This is a note. - </div> - - <div class="callout important"> - This is important. - </div> </body> </html> diff --git a/rss.xml b/rss.xml @@ -7,6 +7,17 @@ <language>en-us</language> <item> + <title>JXL and Compression on nix</title> + <description>Showcase of a script and flake I made for compressing JPG/JEPG to JXL and compressing into a tarball or .7z file</description> + <category>scripting</category> + <category>compression</category> + <category>nix</category> + <pubDate>Tue, 01 June 2026 23:23:00 +0000</pubDate> + <link>./blogs/jxl_and_compression_on_nix.html</link> + <guid>./blogs/jxl_and_compression_on_nix</guid> + </item> + + <item> <title>On the Blog</title> <description>Post about my thoughts on how the blog should work.</description> <category>website</category> @@ -21,7 +32,7 @@ <title>Website</title> <description>Overview of the point of this website.</description> <category>website</category> - <pubDate>Tue, 19 May 2026 23:23:00 +0000</pubDate> + <pubDate>Tue, 21 May 2026 23:23:00 +0000</pubDate> <link>./blogs/website.html</link> <guid>./blogs/website.html</guid> </item> diff --git a/styles.css b/styles.css @@ -14,7 +14,6 @@ --text: #eaeaea; --border: #262626; --link: #6aa7ff; - --accent: #6aa7ff; a[href^="http://"]::after, a[href^="https://"]::after { @@ -28,7 +27,6 @@ html.dark { --text: #eaeaea; --border: #262626; --link: #6aa7ff; - --accent: #6aa7ff; } html.light { @@ -38,6 +36,10 @@ html.light { --link: #0645ad; } +html { + scroll-behavior: smooth; +} + a[href^="http"]::after { content: ""; display: inline-block; @@ -129,12 +131,23 @@ blockquote { ul, ol { - padding-left: 1.5em; + padding-left: 2ch; margin: 0; } +ul { + padding-left: 0ch; + list-style: none; +} -li::marker { - color: color-mix(in srgb, var(--text) 50%, transparent); +ul li::before { + content: "* "; + font-family: "Liberation Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; + color: var(--border); + font-weight: 600; +} + +ol li::marker { + color: var(--border); } legend { @@ -219,7 +232,7 @@ button:active { } button:focus-visible { - outline: 2px solid var(--accent); + outline: 2px solid var(--link); outline-offset: 2px; } @@ -232,6 +245,7 @@ code { } pre { + background: var(--bg); position: relative; margin: 1em 0em; @@ -240,12 +254,13 @@ pre { padding: 1rem; overflow-x: auto; + resize: vertical; white-space: pre; word-break: break-word; font-size: 0.9em; + max-height: 32em; - background: var(--bg); border: 0.0625rem solid var(--border); cursor: pointer; @@ -268,10 +283,26 @@ pre::before { pre:hover::before { content: "COPY"; + border-bottom: 0.0625rem solid var(--text); } pre[data-copied="true"]::before { content: "COPIED"; + border: 0.125rem solid var(--link); +} + +details { + display: inline-block; +} + +details summary { + color: var(--link); + text-decoration: underline dotted; + list-style: none; + + text-decoration-thickness: 2px; + text-decoration-color: color-mix(in srgb, currentcolor 50%, transparent); + cursor: help; } abbr[title] { @@ -281,17 +312,37 @@ abbr[title] { cursor: help; } -aside { +aside.left { position: absolute; - left: calc(50% - 60ch - 2.5em - 2ch); + box-sizing: border-box; + left: calc(50% - 60ch - 2.5em); padding-right: 2ch; transform: translateY(calc(-50% - 0.9em)); width: 20ch; border-right: 0.0625rem solid var(--border); } +aside.right { + position: absolute; + box-sizing: border-box; + right: calc(50% - 60ch - 2.5em); + padding-left: 2ch; + transform: translateY(calc(-50% - 0.9em)); + width: 20ch; + border-left: 0.0625rem solid var(--border); +} + +aside.right::before { + content: ""; + position: absolute; + top: 50%; + left: -4.5ch; + width: 4.5ch; + height: 0.0625rem; + background: var(--border); +} -aside::after { +aside.left::after { content: ""; position: absolute; top: 50%; @@ -301,6 +352,26 @@ aside::after { background: var(--border); } +@media (max-width: 134ch) { + aside { + position: static; + left: auto; + transform: none; + + width: auto; + + margin: 1em 0.4em; + padding: 0.15em 0.8em; + + border: none; + border-left: 0.3em solid var(--border); + } + + aside::after { + display: none; + } +} + .callout { position: relative;