summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCollin Williams <96917990+bluedragon1221@users.noreply.github.com>2026-08-16 15:21:39 -0500
committerCollin Williams <96917990+bluedragon1221@users.noreply.github.com>2026-08-16 15:21:39 -0500
commiteef357ebc10246da0da3c8bce427991eeb3f1dce (patch)
treeb7e5cdc91798a4d0395753640683d13f1a908fff
parent32b19799a1355805bf69222ef1abb6d806980ced (diff)
add a logo, changes to css, format older articles
-rw-r--r--Logo.svg18
-rw-r--r--article.js70
-rw-r--r--fib.html587
-rw-r--r--fonts.css37
-rw-r--r--fonts/FiraCode-VF.woff2bin0 -> 113088 bytes
-rw-r--r--fonts/FiraMath-Regular.woff2bin0 -> 99332 bytes
-rw-r--r--fonts/gelasio-latin-italic.woff2bin0 -> 40068 bytes
-rw-r--r--fonts/gelasio-latin.woff2bin0 -> 34832 bytes
-rw-r--r--forgejno.html1
-rw-r--r--minimalnetworkinglaptop.html212
-rw-r--r--no_ai.html1
-rw-r--r--prose.css169
-rw-r--r--reversible.html36
-rw-r--r--soplt.html1
-rw-r--r--style.css2
15 files changed, 648 insertions, 486 deletions
diff --git a/Logo.svg b/Logo.svg
new file mode 100644
index 0000000..77eb306
--- /dev/null
+++ b/Logo.svg
@@ -0,0 +1,18 @@
+<svg version="1.1"
+ viewBox="0 0 960 960"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg">
+
+ <rect
+ x="1"
+ y="1"
+ width="958"
+ height="958"
+ fill="none"
+ stroke="#e6e6e6"
+ stroke-width="40"/>
+
+ <path
+ fill="#e6e6e6"
+ d="m311.93704 145.0l0 52.28067l120.27191 0l0 5.2159424c-26.282684 7.439789 -46.328003 19.367706 -60.135956 35.783752c-13.7127075 16.33519 -20.569061 36.18811 -20.569061 59.558716c0 29.839996 8.332367 53.69586 24.997131 71.567505c16.664764 17.871643 42.56656 30.527374 77.70538 37.967163l0 3.0325317c-42.18564 4.447693 -75.13425 18.235565 -98.845825 41.363586c-23.616333 23.04715 -35.4245 50.986816 -35.4245 83.81888c0 29.273987 5.856476 53.736267 17.569397 73.387024c11.712952 19.650757 30.710785 36.066833 56.99347 49.24817c26.282715 13.100464 61.659607 24.38147 106.13071 33.842896l66.706604 14.192261l-29.853699 94.614624l66.706665 14.1922l26.425537 -83.454956c1.1427002 -4.5286255 2.1425781 -8.895447 2.9996338 -13.100525c0.85705566 -4.205078 1.2855835 -8.046265 1.2855835 -11.52356c0 -12.938721 -4.6661377 -24.219727 -13.998413 -33.842957c-9.332275 -9.704041 -24.23529 -16.820374 -44.709167 -21.348938l-66.706635 -14.919983c-26.94928 -5.9033203 -48.756317 -13.1813965 -65.42105 -21.834167c-16.664764 -8.733704 -28.949066 -19.165527 -36.852936 -31.295654c-7.903839 -12.2109375 -11.855774 -26.524414 -11.855774 -42.94049l0 -10.431885c0 -19.89331 4.23761 -36.794586 12.71283 -50.703735c8.47522 -13.90918 22.235535 -24.583649 41.280975 -32.023438c19.04544 -7.4397583 43.756897 -11.159668 74.13434 -11.159668l76.41986 0l0 -52.159363l-76.41986 0c-30.948822 0 -54.803223 -7.075897 -71.5632 -21.227661c-16.664764 -14.2326355 -24.997131 -34.247253 -24.997131 -60.043915l0 -10.431885c0 -20.37854 4.380432 -37.643692 13.141357 -51.795456c8.85611 -14.151764 20.99759 -24.94754 36.424377 -32.38733c15.522034 -7.439789 33.805664 -11.159683 54.85086 -11.159683l116.84375 0l0 -52.28067z"/>
+</svg> \ No newline at end of file
diff --git a/article.js b/article.js
index 723d97f..292d61c 100644
--- a/article.js
+++ b/article.js
@@ -1,24 +1,63 @@
+function addMetadata() {
+ // Favicon
+ const favicon = document.createElement("link");
+ favicon.rel = "icon";
+ favicon.href = "/Logo.svg";
+ favicon.type = "image/svg+xml";
+ document.head.appendChild(favicon);
+
+ // UTF-8 (for special characters)
+ const charset = document.createElement("meta");
+ charset.setAttribute("charset", "UTF-8");
+ document.head.appendChild(charset);
+
+ // viewport (for mobile)
+ const viewport = document.createElement("meta");
+ viewport.setAttribute("name", "viewport");
+ viewport.setAttribute("content", "width=device-width, initial-scale=1.0");
+ document.head.appendChild(viewport);
+
+ // css
+ const proseCss = document.createElement("link");
+ proseCss.rel = "stylesheet";
+ proseCss.href = "prose.css";
+ document.head.appendChild(proseCss);
+}
+
function addHeader() {
const header = document.querySelector("header");
-
- const h1 = document.createElement('h1');
+
+ // Logo
+ const logoLink = document.createElement("a");
+ logoLink.href = "/writing.html";
+ logoLink.classList.add("header-logo-link");
+ header.appendChild(logoLink);
+
+ // Right-side content
+ const info = document.createElement("div");
+ info.classList.add("header-info");
+
+ const h1 = document.createElement("h1");
h1.textContent = document.title;
- header.appendChild(h1);
-
- const time = document.createElement('time');
+ info.appendChild(h1);
+
+ const time = document.createElement("time");
const metaDate = document.querySelector('meta[property="article:published_time"]');
- const dateString = metaDate.getAttribute('content');
- const displayDate = (new Date(dateString)).toLocaleDateString('en-US', {
- month: 'short',
- day: 'numeric',
- year: 'numeric',
- timeZone: 'UTC'
+ const dateString = metaDate.getAttribute("content");
+ const displayDate = (new Date(dateString)).toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ timeZone: "UTC"
});
- time.setAttribute('datetime', dateString);
- time.textContent = displayDate;
- header.appendChild(time);
- const hr = document.createElement('hr');
+ time.setAttribute("datetime", dateString);
+ time.textContent = `Published ${displayDate}`;
+ info.appendChild(time);
+
+ header.appendChild(info);
+
+ const hr = document.createElement("hr");
header.appendChild(hr);
}
@@ -47,6 +86,7 @@ function addTOC() {
}
document.addEventListener("DOMContentLoaded", () => {
+ addMetadata()
addHeader()
addTOC()
}) \ No newline at end of file
diff --git a/fib.html b/fib.html
index 998308e..29d5e71 100644
--- a/fib.html
+++ b/fib.html
@@ -1,55 +1,55 @@
<!DOCTYPE html>
<html>
-<head>
- <title>I accidentally derived a formula for the Fibonacci Sequence</title>
- <meta property="article:published_time" content="2026-06-11">
- <link rel="stylesheet" href="prose.css">
- <script src="article.js"></script>
-</head>
-<body>
- <article>
- <header></header>
+ <head>
+ <title>I accidentally derived a formula for the Fibonacci Sequence</title>
+ <meta property="article:published_time" content="2026-06-11">
+ <script src="article.js"></script>
+ </head>
+ <body>
+ <article>
+ <header></header>
- <p>Last night my brother pitched me this math problem over dinner (which he later revealed came from <a href="https://www.youtube.com/watch?v=XeOTNEb-QsM">this video</a>). It goes something like this:</p>
- <blockquote>
- <p>There is a flight of <math><mi>n</mi></math> stairs in front of you.</p>
- <p>You can only ascend in steps of 1 or 2 stairs.</p>
- <p>How many different ways are there for you to go up the stairs?</p>
- </blockquote>
- <p>For the rest of the article, I will go over my thought process (and stupidity) when solving the problem. Enjoy!</p>
- <hr>
- <p>First, I drew out some stairs and some tables to get base-cases and a feel for the problem.</p>
- <table>
- <thead>
- <tr>
- <th><strong># of stairs</strong></th>
- <th><strong># of ways to ascend</strong></th>
- </tr>
- </thead>
- <tbody>
- <tr><td>1</td><td>1</td></tr>
- <tr><td>2</td><td>2</td></tr>
- <tr><td>3</td><td>3</td></tr>
- <tr><td>4</td><td>5</td></tr>
- <tr><td>5</td><td>8</td></tr>
- </tbody>
- </table>
+ <p>Last night my brother pitched me this math problem over dinner (which he later revealed came from <a href="https://www.youtube.com/watch?v=XeOTNEb-QsM">this video</a>). It goes something like this:</p>
+ <blockquote>
+ <p>There is a flight of <math><mi>n</mi></math>
+ stairs in front of you.</p>
+ <p>You can only ascend in steps of 1 or 2 stairs.</p>
+ <p>How many different ways are there for you to go up the stairs?</p>
+ </blockquote>
+ <p>For the rest of the article, I will go over my thought process (and stupidity) when solving the problem. Enjoy!</p>
+ <hr>
+ <p>First, I drew out some stairs and some tables to get base-cases and a feel for the problem.</p>
+ <table>
+ <thead>
+ <tr>
+ <th><strong># of stairs</strong></th>
+ <th><strong># of ways to ascend</strong></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td>1</td><td>1</td></tr>
+ <tr><td>2</td><td>2</td></tr>
+ <tr><td>3</td><td>3</td></tr>
+ <tr><td>4</td><td>5</td></tr>
+ <tr><td>5</td><td>8</td></tr>
+ </tbody>
+ </table>
- <p>Now, if you already see a familiar pattern in these numbers, shh! I somehow failed to see it, although it's obvious in hindsight, but I guess that's a good thing since it led me to the results of this article.</p>
- <p>Next, I decided to take a look at the lengths of jumps. I made a list of numbers, where each number represented a jump of that height. So, for example, one ascent of the 10-stair staircase example might look like:</p>
- <pre><code>[1 2 2 1 2 1 1]</code></pre>
- <p>Since this list encodes a sequence of jumps that would climb 10 stairs, it's trivial to say the list must sum to 10.</p>
- <p>This allowed me to rewrite the problem as the following:</p>
- <blockquote>
- <p>For any <math><mi>n</mi></math>, how many unique sequences of 2s and 1s add to <math><mi>n</mi></math>?</p>
- </blockquote>
- <p>While this was definitely more abstract, it reframed the problem using numbers, which I could play with using math.</p>
- <hr>
+ <p>Now, if you already see a familiar pattern in these numbers, shh! I somehow failed to see it, although it's obvious in hindsight, but I guess that's a good thing since it led me to the results of this article.</p>
+ <p>Next, I decided to take a look at the lengths of jumps. I made a list of numbers, where each number represented a jump of that height. So, for example, one ascent of the 10-stair staircase example might look like:</p>
+ <pre><code>[1 2 2 1 2 1 1]</code></pre>
+ <p>Since this list encodes a sequence of jumps that would climb 10 stairs, it's trivial to say the list must sum to 10.</p>
+ <p>This allowed me to rewrite the problem as the following:</p>
+ <blockquote>
+ <p>For any <math><mi>n</mi></math>, how many unique sequences of 2s and 1s add to <math><mi>n</mi></math>?</p>
+ </blockquote>
+ <p>While this was definitely more abstract, it reframed the problem using numbers, which I could play with using math.</p>
+ <hr>
- <p>Next, since I had no idea how I would go about counting the sequences, I looked at how I could group them, in hoping that would make them easier to count.</p>
- <p>Arbitrarily, I decided to group the sequences by how many 2s were in them.</p>
- <p>For the 5-stair staircase example, all of the possible sequences of 1s and 2s that sum to 5 look like:</p>
- <pre><code>[1 1 2 1]
+ <p>Next, since I had no idea how I would go about counting the sequences, I looked at how I could group them, in hoping that would make them easier to count.</p>
+ <p>Arbitrarily, I decided to group the sequences by how many 2s were in them.</p>
+ <p>For the 5-stair staircase example, all of the possible sequences of 1s and 2s that sum to 5 look like:</p>
+ <pre><code>[1 1 2 1]
[2 1 2]
[1 2 1 1]
[1 1 1 1 1]
@@ -57,247 +57,262 @@
[1 2 2]
[1 1 1 2]
[2 2 1]</code></pre>
- <p>Grouping each sequence by the number of 2s in it yields the table:</p>
- <table>
- <tbody>
- <tr>
- <th scope="row"># of 2s (<math><mi>t</mi></math>)</th>
- <td>0</td>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <th scope="row"></th>
- <td><code>[1 1 1 1 1]</code></td>
- <td><code>[2 1 1 1]<br>[1 2 1 1]<br>[1 1 2 1]<br>[1 1 1 2]</code></td>
- <td><code>[1 2 2]<br>[2 1 2]<br>[2 2 1]</code></td>
- <td></td>
- </tr>
- <tr>
- <th scope="row">length of sequences (<math><msub><mi>k</mi><mi>t</mi></msub></math>)</th>
- <td>5</td>
- <td>4</td>
- <td>3</td>
- </tr>
- <tr>
- <th scope="row"># of sequences (<math><msub><mi>m</mi><mi>t</mi></msub></math>)</th>
- <td>1</td>
- <td>4</td>
- <td>3</td>
- <td>0</td>
- </tr>
- </tbody>
- </table>
- <p>This adds to a grand total of 8 sequences for a 5-stair staircase.</p>
+ <p>Grouping each sequence by the number of 2s in it yields the table:</p>
+ <table>
+ <tbody>
+ <tr>
+ <th scope="row"># of 2s (<math><mi>t</mi></math>)</th>
+ <td>0</td>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <th scope="row">sequences</th>
+ <td><code>[1 1 1 1 1]</code></td>
+ <td><code>[2 1 1 1]<br>[1 2 1 1]<br>[1 1 2 1]<br>[1 1 1 2]</code></td>
+ <td><code>[1 2 2]<br>[2 1 2]<br>[2 2 1]</code></td>
+ <td></td>
+ </tr>
+ <tr>
+ <th scope="row">length of sequences (<math><msub><mi>k</mi><mi>t</mi></msub></math>)</th>
+ <td>5</td>
+ <td>4</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <th scope="row"># of sequences (<math><msub><mi>m</mi><mi>t</mi></msub></math>)</th>
+ <td>1</td>
+ <td>4</td>
+ <td>3</td>
+ <td>0</td>
+ </tr>
+ </tbody>
+ </table>
+ <p>This adds to a grand total of 8 sequences for a 5-stair staircase.</p>
- <p>From the table, I made a few insights:</p>
- <ul>
- <li><p>
- Any two sequences with the same number of 2s have the same length.
- This made sense because sequences with the same number of 2s always have the same number of 1s, so their total length must be the same.
- </p></li>
- <li><p>
- <math><mi>k</mi></math> seemed to follow the pattern <math><mi>k</mi><mo>=</mo><mn>n</mn><mo>-</mo><mn>t</mn></math>.
- This made sense because with each introduction of one more 2, then length of the list must decrease by 1 to still sum to 5.
- </p></li>
- <li><p>
- The pattern <math><mi>k</mi><mo>=</mo><mn>n</mn><mo>-</mo><mn>t</mn></math> only worked for <math><mn>2</mn><mi>t</mi><mo>&le;</mo><mi>n</mi></math>.
- This made sense because if the sequence must sum to 5, then it can not contain 3 2s. This allowed me to define a general maximum for <math><mi>t</mi></math>.
- <math display="block">
- <mrow>
- <msub>
- <mi>t</mi>
- <mi>max</mi>
- </msub>
- <mo>=</mo>
- <mo>&lfloor;</mo>
- <mfrac>
- <mi>n</mi>
- <mn>2</mn>
- </mfrac>
- <mo>&rfloor;</mo>
- </mrow>
- </math>
- </p></li>
- </ul>
- <hr>
+ <p>From the table, I made a few insights:</p>
+ <ul>
+ <li><p>
+ Any two sequences with the same number of 2s have the same length.
+ This made sense because sequences with the same number of 2s always have the same number of 1s, so their total length must be the same.
+ </p></li>
+ <li><p>
+ <math><mi>k</mi></math>
+ seemed to follow the pattern <math><mi>k</mi><mo>=</mo><mn>n</mn><mo>-</mo><mn>t</mn></math>.
+ This made sense because with each introduction of one more 2, then length of the list must decrease by 1 to still sum to 5.
+ </p></li>
+ <li><p>
+ The pattern <math><mi>k</mi><mo>=</mo><mn>n</mn><mo>-</mo><mn>t</mn></math>
+ only worked for <math><mn>2</mn><mi>t</mi><mo>&le;</mo><mi>n</mi></math>.
+ This made sense because if the sequence must sum to 5, then it can not contain 3 2s. This allowed me to define a general maximum for <math><mi>t</mi></math>.
+ <math display="block">
+ <mrow>
+ <msub>
+ <mi>t</mi>
+ <mi>max</mi>
+ </msub>
+ <mo>=</mo>
+ <mo>&lfloor;</mo>
+ <mfrac>
+ <mi>n</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>&rfloor;</mo>
+ </mrow>
+ </math>
+ </p></li>
+ </ul>
+ <hr>
- <p>Okay, so now that I had a way to split the sequences into pieces, I just needed a way to count the number of sequences for each value of <math><mi>t</mi></math>, and sum those together.</p>
- <p>The sum is the easy part. I knew the final number would be the the sum of all of the <math><msub><mi>m</mi><mi>t</mi></msub></math>s, or:</p>
- <math display="block">
- <mrow>
- <munderover>
- <mo>∑</mo>
- <mrow>
- <mi>t</mi>
- <mo>=</mo>
- <mn>0</mn>
- </mrow>
- <msub>
- <mi>t</mi>
- <mi>max</mi>
- </msub>
- </munderover>
- <msub><mi>m</mi><mi>t</mi></msub>
- </mrow>
- </math>
- <p>Plugging in our definition for <math><msub><mi>t</mi><mi>max</mi></msub></math>,</p>
- <math display="block">
- <mrow>
- <munderover>
- <mo>∑</mo>
- <mrow>
- <mi>t</mi>
- <mo>=</mo>
- <mn>0</mn>
- </mrow>
- <mrow>
- <mo>&lfloor;</mo>
- <mfrac>
- <mi>n</mi>
- <mn>2</mn>
- </mfrac>
- <mo>&rfloor;</mo>
- </mrow>
- </munderover>
- <msub><mi>m</mi><mi>t</mi></msub>
- </mrow>
- </math>
+ <p>Okay, so now that I had a way to split the sequences into pieces, I just needed a way to count the number of sequences for each value of <math><mi>t</mi></math>, and sum those together.</p>
+ <p>The sum was the easy part. I knew the final number would be the the sum of all of the <math><msub><mi>m</mi><mi>t</mi></msub></math>s, or:</p>
+ <math display="block">
+ <mrow>
+ <munderover>
+ <mo>∑</mo>
+ <mrow>
+ <mi>t</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ </mrow>
+ <msub>
+ <mi>t</mi>
+ <mi>max</mi>
+ </msub>
+ </munderover>
+ <msub><mi>m</mi><mi>t</mi></msub>
+ </mrow>
+ </math>
+ <p>Plugging in our definition for <math><msub><mi>t</mi><mi>max</mi></msub></math>,</p>
+ <math display="block">
+ <mrow>
+ <munderover>
+ <mo>∑</mo>
+ <mrow>
+ <mi>t</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ </mrow>
+ <mrow>
+ <mo>&lfloor;</mo>
+ <mfrac>
+ <mi>n</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>&rfloor;</mo>
+ </mrow>
+ </munderover>
+ <msub><mi>m</mi><mi>t</mi></msub>
+ </mrow>
+ </math>
- <p>After thinking about the sequences for a while, I realized that the number of sequences boils down to the question "how many ways can you uniquely arrange a list of <math><mi>t</mi></math> special items out of <math><mi>k</mi></math> total items?"</p>
- <p>Then I realized: this was a combinatorics problem! Specifically, I remembered the Binomial Coefficient, or "<math><mi>n</mi></math> choose <math><mi>k</mi></math>", which counts "the number of ways to choose a subset of k elements from a larger set of n elements."</p>
- <p>Each sequence of length <math><mi>k</mi></math> contained exactly <math><mi>t</mi></math> 2s. So counting the number of sequences <math><msub><mi>m</mi><mi>t</mi></msub></math> for some <math><mi>t</mi></math> was equivelant to counting the number of ways to choose <math><mi>t</mi></math> elements from a larger set of <math><mi>k</mi></math> elements. By this definition,</p>
- <math display="block">
- <mrow>
- <msub><mi>m</mi><mi>t</mi></msub>
- <mo>=</mo>
- <mo>(</mo>
- <mfrac linethickness="0">
- <mrow>
- <mi>k</mi>
- </mrow>
- <mi>t</mi>
- </mfrac>
- <mo>)</mo>
- </mrow>
- </math>
- <p>Plugging in the prior definition for <math><mi>k</mi></math>, and using the summation from above, I arrived at a final equation:</p>
- <math display="block">
- <mi>f</mi><mo>(</mo><mi>n</mi><mo>)</mo>
- <mo>=</mo>
- <mrow>
- <munderover>
- <mo>∑</mo>
- <mrow>
- <mi>t</mi>
- <mo>=</mo>
- <mn>0</mn>
- </mrow>
- <mrow>
- <mo>&lfloor;</mo>
- <mfrac>
- <mi>n</mi>
- <mn>2</mn>
- </mfrac>
- <mo>&rfloor;</mo>
- </mrow>
- </munderover>
+ <p>After thinking about the sequences for a while, I realized that the number of sequences boils down to the question "how many ways can you uniquely arrange a list of <math><mi>t</mi></math>
+ special items out of <math><mi>k</mi></math>
+ total items?"</p>
+ <p>Then I realized: this was a combinatorics problem! Specifically, I remembered the Binomial Coefficient, or "<math><mi>n</mi></math>
+ choose <math><mi>k</mi></math>", which counts "the number of ways to choose a subset of k elements from a larger set of n elements."</p>
+ <p>Each sequence of length <math><mi>k</mi></math>
+ contained exactly <math><mi>t</mi></math>
+ 2s. So counting the number of sequences <math><msub><mi>m</mi><mi>t</mi></msub></math>
+ for some <math><mi>t</mi></math>
+ was equivelant to counting the number of ways to choose <math><mi>t</mi></math>
+ elements from a larger set of <math><mi>k</mi></math>
+ elements. By this definition,</p>
+ <math display="block">
+ <mrow>
+ <msub><mi>m</mi><mi>t</mi></msub>
+ <mo>=</mo>
+ <mo>(</mo>
+ <mfrac linethickness="0">
+ <mrow>
+ <mi>k</mi>
+ </mrow>
+ <mi>t</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </math>
+ <p>Plugging in the prior definition for <math><mi>k</mi></math>, and using the summation from above, I arrived at a final equation:</p>
+ <math display="block">
+ <mi>f</mi><mo>(</mo><mi>n</mi><mo>)</mo>
+ <mo>=</mo>
+ <mrow>
+ <munderover>
+ <mo>∑</mo>
+ <mrow>
+ <mi>t</mi>
+ <mo>=</mo>
+ <mn>0</mn>
+ </mrow>
+ <mrow>
+ <mo>&lfloor;</mo>
+ <mfrac>
+ <mi>n</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>&rfloor;</mo>
+ </mrow>
+ </munderover>
- <mrow>
- <mo>(</mo>
- <mfrac linethickness="0">
- <mrow>
- <mi>n</mi>
- <mo>-</mo>
- <mi>t</mi>
- </mrow>
- <mi>t</mi>
- </mfrac>
- <mo>)</mo>
- </mrow>
- </mrow>
- </math>
- <p>Yay!</p>
- <hr>
+ <mrow>
+ <mo>(</mo>
+ <mfrac linethickness="0">
+ <mrow>
+ <mi>n</mi>
+ <mo>-</mo>
+ <mi>t</mi>
+ </mrow>
+ <mi>t</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </mrow>
+ </math>
+ <p>Yay!</p>
+ <hr>
- <p>Okay, if you didn't see the pattern from the beginning, <code>[1 2 3 5 8]</code> is the <strong>Fibonacci Sequence</strong>, starting at the 2nd element. You might be more familiar with it starting from the 1st element <code>[1 1 2 3 5 8 ...]</code>.</p>
- <p>So we really just derived a formula for the <math><mi>n</mi><mo>+</mo><mn>1</mn></math>th Fibonacci number!</p>
- <p>When I first learned this, I thought I was some kind of genius or something, but a quick check on ProofWiki told that <a href="https://proofwiki.org/wiki/Fibonacci_Number_as_Sum_of_Binomial_Coefficients">a very similar function was already discovered in 1971</a>, so I guess I'm 55 years late to the party.</p>
- <p>The formula on ProofWiki is for the <math><mi>n</mi></math>th fibonacci number, so here's how you could arrive at the real Fibonacci Number as Sum of Binomial Coefficients function:</p>
- <p>Begin with the derived formula, replacing <math><mi>n</mi></math> for <math><mi>a</mi></math> to avoid variable conflicts later.</p>
- <math display="block">
- <mi>f</mi><mo>(</mo><mi>a</mi><mo>)</mo>
- <mo>=</mo>
- <mrow>
- <munderover>
- <mo>∑</mo>
- <mrow><mi>t</mi><mo>=</mo><mn>0</mn></mrow>
- <mrow>
- <mo>&lfloor;</mo>
- <mfrac><mi>a</mi><mn>2</mn></mfrac>
- <mo>&rfloor;</mo>
- </mrow>
- </munderover>
- <mrow>
- <mo>(</mo>
- <mfrac linethickness="0">
- <mrow><mi>a</mi><mo>-</mo><mi>t</mi></mrow>
- <mi>t</mi>
- </mfrac>
- <mo>)</mo>
- </mrow>
- </mrow>
- </math>
- <p>Since this is really for the <math><mi>n</mi><mo>+</mo><mn>1</mn></math>th Fibonacci number, substitute <math><mi>a</mi><mo>=</mo><mi>n</mi><mo>-</mo><mn>1</mn></math>.</p>
- <math display="block">
- <mi>f</mi><mo>(</mo><mi>n</mi><mo>)</mo>
- <mo>=</mo>
- <mrow>
- <munderover>
- <mo>∑</mo>
- <mrow><mi>t</mi><mo>=</mo><mn>0</mn></mrow>
- <mrow>
- <mo>&lfloor;</mo>
- <mfrac><mrow><mi>n</mi><mo>-</mo><mn>1</mn></mrow><mn>2</mn></mfrac>
- <mo>&rfloor;</mo>
- </mrow>
- </munderover>
- <mrow>
- <mo>(</mo>
- <mfrac linethickness="0">
- <mrow><mi>n</mi><mo>-</mo><mi>t</mi><mo>-</mo><mn>1</mn></mrow>
- <mi>t</mi>
- </mfrac>
- <mo>)</mo>
- </mrow>
- </mrow>
- </math>
- <p>The original function uses <math><mi>k</mi></math> instead of <math><mi>t</mi></math>.</p>
- <math display="block">
- <mi>f</mi><mo>(</mo><mi>n</mi><mo>)</mo>
- <mo>=</mo>
- <mrow>
- <munderover>
- <mo>∑</mo>
- <mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow>
- <mrow>
- <mo>&lfloor;</mo>
- <mfrac><mrow><mi>n</mi><mo>-</mo><mn>1</mn></mrow><mn>2</mn></mfrac>
- <mo>&rfloor;</mo>
- </mrow>
- </munderover>
- <mrow>
- <mo>(</mo>
- <mfrac linethickness="0">
- <mrow><mi>n</mi><mo>-</mo><mi>k</mi><mo>-</mo><mn>1</mn></mrow>
- <mi>k</mi>
- </mfrac>
- <mo>)</mo>
- </mrow>
- </mrow>
- </math>
- <p>This is the exact same function that appears on ProofWiki!</p>
- </article>
-</body>
-</html> \ No newline at end of file
+ <p>Okay, if you didn't see the pattern from the beginning, <code>[1 2 3 5 8]</code>
+ is the <strong>Fibonacci Sequence</strong>, starting at the 2nd element. You might be more familiar with it starting from the 1st element <code>[1 1 2 3 5 8 ...]</code>.</p>
+ <p>So we really just derived a formula for the <math><mi>n</mi><mo>+</mo><mn>1</mn></math>th Fibonacci number!</p>
+ <p>When I first learned this, I thought I was some kind of genius or something, but a quick check on ProofWiki told that <a href="https://proofwiki.org/wiki/Fibonacci_Number_as_Sum_of_Binomial_Coefficients">a very similar function was already discovered in 1971</a>, so I guess I'm 55 years late to the party.</p>
+ <p>The formula on ProofWiki is for the <math><mi>n</mi></math>th fibonacci number, so here's how you could arrive at the real Fibonacci Number as Sum of Binomial Coefficients function:</p>
+ <p>Begin with the derived formula, replacing <math><mi>n</mi></math>
+ for <math><mi>a</mi></math>
+ to avoid variable conflicts later.</p>
+ <math display="block">
+ <mi>f</mi><mo>(</mo><mi>a</mi><mo>)</mo>
+ <mo>=</mo>
+ <mrow>
+ <munderover>
+ <mo>∑</mo>
+ <mrow><mi>t</mi><mo>=</mo><mn>0</mn></mrow>
+ <mrow>
+ <mo>&lfloor;</mo>
+ <mfrac><mi>a</mi><mn>2</mn></mfrac>
+ <mo>&rfloor;</mo>
+ </mrow>
+ </munderover>
+ <mrow>
+ <mo>(</mo>
+ <mfrac linethickness="0">
+ <mrow><mi>a</mi><mo>-</mo><mi>t</mi></mrow>
+ <mi>t</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </mrow>
+ </math>
+ <p>Since this is really for the <math><mi>n</mi><mo>+</mo><mn>1</mn></math>th Fibonacci number, substitute <math><mi>a</mi><mo>=</mo><mi>n</mi><mo>-</mo><mn>1</mn></math>.</p>
+ <math display="block">
+ <mi>f</mi><mo>(</mo><mi>n</mi><mo>)</mo>
+ <mo>=</mo>
+ <mrow>
+ <munderover>
+ <mo>∑</mo>
+ <mrow><mi>t</mi><mo>=</mo><mn>0</mn></mrow>
+ <mrow>
+ <mo>&lfloor;</mo>
+ <mfrac><mrow><mi>n</mi><mo>-</mo><mn>1</mn></mrow><mn>2</mn></mfrac>
+ <mo>&rfloor;</mo>
+ </mrow>
+ </munderover>
+ <mrow>
+ <mo>(</mo>
+ <mfrac linethickness="0">
+ <mrow><mi>n</mi><mo>-</mo><mi>t</mi><mo>-</mo><mn>1</mn></mrow>
+ <mi>t</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </mrow>
+ </math>
+ <p>The original function uses <math><mi>k</mi></math>
+ instead of <math><mi>t</mi></math>.</p>
+ <math display="block">
+ <mi>f</mi><mo>(</mo><mi>n</mi><mo>)</mo>
+ <mo>=</mo>
+ <mrow>
+ <munderover>
+ <mo>∑</mo>
+ <mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow>
+ <mrow>
+ <mo>&lfloor;</mo>
+ <mfrac><mrow><mi>n</mi><mo>-</mo><mn>1</mn></mrow><mn>2</mn></mfrac>
+ <mo>&rfloor;</mo>
+ </mrow>
+ </munderover>
+ <mrow>
+ <mo>(</mo>
+ <mfrac linethickness="0">
+ <mrow><mi>n</mi><mo>-</mo><mi>k</mi><mo>-</mo><mn>1</mn></mrow>
+ <mi>k</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </mrow>
+ </math>
+ <p>This is the exact same function that appears on ProofWiki!</p>
+ </article>
+ </body>
+</html>
diff --git a/fonts.css b/fonts.css
new file mode 100644
index 0000000..7ce76d4
--- /dev/null
+++ b/fonts.css
@@ -0,0 +1,37 @@
+@font-face {
+ font-family: "Gelasio";
+ font-style: normal;
+ font-weight: 400 700;
+ font-display: swap;
+ src: url("/fonts/gelasio-latin.woff2") format("woff2");
+}
+
+@font-face {
+ font-family: "Gelasio";
+ font-style: italic;
+ font-weight: 400 700;
+ font-display: swap;
+ src: url("/fonts/gelasio-latin-italic.woff2") format("woff2");
+}
+
+@font-face {
+ font-family: "Fira Math";
+ src: url("/fonts/FiraMath-Regular.woff2") format("woff2");
+ font-weight: 400;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "Fira Code";
+ src: url("/fonts/FiraCode-VF.woff2") format("woff2");
+ font-style: normal;
+ font-weight: 300 700;
+ font-display: swap;
+}
+
+:root {
+ --fontSerif: 'Gelasio', serif;
+ --fontMono: 'Fira Code', monospace;
+ --fontMath: 'Fira Math', serif;
+} \ No newline at end of file
diff --git a/fonts/FiraCode-VF.woff2 b/fonts/FiraCode-VF.woff2
new file mode 100644
index 0000000..e755a9d
--- /dev/null
+++ b/fonts/FiraCode-VF.woff2
Binary files differ
diff --git a/fonts/FiraMath-Regular.woff2 b/fonts/FiraMath-Regular.woff2
new file mode 100644
index 0000000..fd08e65
--- /dev/null
+++ b/fonts/FiraMath-Regular.woff2
Binary files differ
diff --git a/fonts/gelasio-latin-italic.woff2 b/fonts/gelasio-latin-italic.woff2
new file mode 100644
index 0000000..7f95e1d
--- /dev/null
+++ b/fonts/gelasio-latin-italic.woff2
Binary files differ
diff --git a/fonts/gelasio-latin.woff2 b/fonts/gelasio-latin.woff2
new file mode 100644
index 0000000..fe18998
--- /dev/null
+++ b/fonts/gelasio-latin.woff2
Binary files differ
diff --git a/forgejno.html b/forgejno.html
index e36b358..100c606 100644
--- a/forgejno.html
+++ b/forgejno.html
@@ -3,7 +3,6 @@
<head>
<title>You don't need Forgejo</title>
<meta property="article:published_time" content="2026-05-03">
- <link rel="stylesheet" href="prose.css">
<script src="article.js"></script>
</head>
<body>
diff --git a/minimalnetworkinglaptop.html b/minimalnetworkinglaptop.html
index f9ca405..bc07c9b 100644
--- a/minimalnetworkinglaptop.html
+++ b/minimalnetworkinglaptop.html
@@ -1,52 +1,49 @@
<!DOCTYPE html>
<html>
-<head>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <head>
+ <title>Minimal Laptop Networking with NixOS</title>
+ <meta property="article:published_time" content="2026-07-29">
+ <script src="article.js"></script>
+ </head>
+ <body>
+ <article>
+ <header></header>
- <title>Minimal Laptop Networking with NixOS</title>
- <link rel="stylesheet" href="prose.css">
- <meta property="article:published_time" content="2026-07-29">
- <script src="article.js"></script>
-</head>
-<body>
- <article>
- <header></header>
+ <p>
+ The default networking stack on NixOS uses NetworkManager.
+ While it's a great choice for many users, I prefer a lighter setup built around systemd-networkd, systemd-resolved, and iwd. It integrates well with the rest of the systemd stack, has fewer moving pieces, and exposes powerful networking features without an additional network management daemon.
+ </p>
- <p>
- The default networking stack on NixOS uses NetworkManager.
- While it's a great choice for many users, I prefer a lighter setup built around systemd-networkd, systemd-resolved, and iwd. It integrates well with the rest of the systemd stack, has fewer moving pieces, and exposes powerful networking features without an additional network management daemon.
- </p>
+ <p class="comment">
+ This article focuses on laptops that connect to wifi.
+ If you're configuring a server, you probably don't need iwd at all; systemd-networkd and systemd-resolved are usually sufficient.
+ </p>
- <p class="comment">
- This article focuses on laptops that connect to wifi.
- If you're configuring a server, you probably don't need iwd at all; systemd-networkd and systemd-resolved are usually sufficient.
- </p>
+ <div id="toc"></div>
- <div id="toc"></div>
+ <h2>The default stack</h2>
+ <p>If not configured otherwise, NixOS uses the following stack:</p>
+ <ul>
+ <li>NetworkManager for wifi</li>
+ <li>dhcpcd for DHCP</li>
+ <li>resolvconf for DNS</li>
+ <li>a "legacy script based system" for network configuration<sup><a href="https://search.nixos.org/options?channel=26.05&query=useNetworkd&type=options#show=option%253Anetworking.useNetworkd:~:text=legacy%20script%20based%20system">[1]</a></sup></li>
+ </ul>
+ <p>We'll be replacing it with:</p>
+ <ul>
+ <li>iwd for wifi</li>
+ <li>systemd-networkd for DHCP and network configuration</li>
+ <li>systemd-resolved for DNS</li>
+ </ul>
+ <p>
+ This has a few benefits.
+ Firstly, switching to resolved allows you to enable features like encrypted DNS over TLS (DoT) and DNSSEC validation, which reduces the potential for DNS spoofing and man-in-the-middle attacks<sup><a href="https://whynothugo.nl/journal/2026/06/24/ignore-dnssec-if-you-like-mitm-attacks/#distributions-and-oss">[2]</a></sup>.
+ Additionally, the default stack uses 3 extra packages (NM, dhcpcd, resolvconf) and some bash scripts, while this setup only uses one extra package (iwd).
+ Also, I'm kind of a systemd nerd, and this is a way to dig into systemd a bit more.
+ </p>
- <h2>The default stack</h2>
- <p>If not configured otherwise, NixOS uses the following stack:</p>
- <ul>
- <li>NetworkManager for wifi</li>
- <li>dhcpcd for DHCP</li>
- <li>resolvconf for DNS</li>
- <li>a "legacy script based system" for network configuration<sup><a href="https://search.nixos.org/options?channel=26.05&query=useNetworkd&type=options#show=option%253Anetworking.useNetworkd:~:text=legacy%20script%20based%20system">[1]</a></sup></li>
- </ul>
- <p>We'll be replacing it with:</p>
- <ul>
- <li>iwd for wifi</li>
- <li>systemd-networkd for DHCP and network configuration</li>
- <li>systemd-resolved for DNS</li>
- </ul>
- <p>
- This has a few benefits.
- Firstly, switching to resolved allows you to enable features like encrypted DNS over TLS (DoT) and DNSSEC validation, which reduces the potential for DNS spoofing and man-in-the-middle attacks<sup><a href="https://whynothugo.nl/journal/2026/06/24/ignore-dnssec-if-you-like-mitm-attacks/#distributions-and-oss">[2]</a></sup>.
- Additionally, the default stack uses 3 extra packages (NM, dhcpcd, resolvconf) and some bash scripts, while this setup only uses one extra package (iwd).
- Also, I'm kind of a systemd nerd, and this is a way to dig into systemd a bit more.
- </p>
-
- <p>So the first thing we can do is disable all of the default stuff:</p>
- <pre><code>{
+ <p>So the first thing we can do is disable all of the default stuff:</p>
+ <pre><code>{
<prop>networking</prop> = {
<prop>networkmanager</prop>.<prop>enable</prop> = <kw>false</kw>;
<prop>dhcpcd</prop>.<prop>enable</prop> = <kw>false</kw>;
@@ -55,14 +52,14 @@
};
}</code></pre>
- <p>And let's get to configuring!</p>
+ <p>And let's get to configuring!</p>
- <h2>iwd</h2>
- <p>
- First up is iwd.
- The important parts of the configuration are delegating network configuration to networkd, delegating name resolution (DNS) to resolved, and configuring MAC randomization for some extra privacy.
- </p>
- <pre><code>{
+ <h2>iwd</h2>
+ <p>
+ First up is iwd.
+ The important parts of the configuration are delegating network configuration to networkd, delegating name resolution (DNS) to resolved, and configuring MAC randomization for some extra privacy.
+ </p>
+ <pre><code>{
<prop>networking</prop>.<prop>wireless</prop>.<prop>iwd</prop> = {
<prop>enable</prop> = <kw>true</kw>;
<prop>settings</prop> = {
@@ -76,28 +73,28 @@
};
}</code></pre>
- <p>
- At this point, we don't have any network configuration yet, so internet access won't work. However, you can verify that iwd is functioning correctly:
- </p>
- <ul>
- <li><code>iwctl station wlan0 scan</code>: Scans for new wifi networks</li>
- <li><code>iwctl station wlan0 get-networks</code>: lists the networks that it found</li>
- <li><code>iwctl station wlan0 connect "&lt;SSID&gt;"</code>: connects to the network, prompting for a PSK if necessary</li>
- </ul>
+ <p>
+ At this point, we don't have any network configuration yet, so internet access won't work. However, you can verify that iwd is functioning correctly:
+ </p>
+ <ul>
+ <li><code><kw>iwctl</kw> <prop>station</prop> <prop>wlan0</prop> <prop>scan</prop></code>: Scans for new wifi networks</li>
+ <li><code><kw>iwctl</kw> <prop>station</prop> <prop>wlan0</prop> <prop>get-networks</prop></code>: lists the networks that it found</li>
+ <li><code><kw>iwctl</kw> <prop>station</prop> <prop>wlan0</prop> <prop>connect</prop> <str>"&lt;SSID&gt;"</str></code>: connects to the network, prompting for a PSK if necessary</li>
+ </ul>
- <h2>systemd-networkd</h2>
- <p>
- Next up is systemd-networkd.
- Networkd has lots of advanced options for things like static IP config, Wireguard tunnels, VLANs, domain-based DNS routing, and more.
- However, here we'll just do a basic configuration to enable DHCP and deny DHCP-advertised DNS.
- </p>
- <details class="comment">
- <summary>why disable DHCP-advertised DNS?</summary>
- By default, most networks advertise their own DNS resolver via DHCP.
- Since we'll configure our own encrypted upstream DNS servers in the next section, we tell networkd to ignore the ones provided by the network.
- </details>
+ <h2>systemd-networkd</h2>
+ <p>
+ Next up is systemd-networkd.
+ Networkd has lots of advanced options for things like static IP config, Wireguard tunnels, VLANs, domain-based DNS routing, and more.
+ However, here we'll just do a basic configuration to enable DHCP and deny DHCP-advertised DNS.
+ </p>
+ <details class="comment">
+ <summary>why disable DHCP-advertised DNS?</summary>
+ By default, most networks advertise their own DNS resolver via DHCP.
+ Since we'll configure our own encrypted upstream DNS servers in the next section, we tell networkd to ignore the ones provided by the network.
+ </details>
- <pre><code>{
+ <pre><code>{
<prop>systemd</prop>.<prop>network</prop> = {
<prop>enable</prop> = <kw>true</kw>;
@@ -113,27 +110,28 @@
<prop>networking</prop>.<prop>useNetworkd</prop> = <kw>true</kw>;
}</code></pre>
- <p>
- The <code>name = "wl*"</code> refers to the network interface name that this configuration applies to.
- According to the systemd docs, wireless LAN devices should start with the two-character prefix "wl"<sup><a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.net-naming-scheme.html#:~:text=wl,WLAN">[3]</a></sup>.
- Here we use a glob (<code>*</code>) to match all wireless interfaces.
- </p>
+ <p>
+ The <code>name = "wl*"</code>
+ refers to the network interface name that this configuration applies to.
+ According to the systemd docs, wireless LAN devices should start with the two-character prefix "wl"<sup><a href="https://www.freedesktop.org/software/systemd/man/latest/systemd.net-naming-scheme.html#:~:text=wl,WLAN">[3]</a></sup>.
+ Here we use a glob (<code>*</code>) to match all wireless interfaces.
+ </p>
- <p>You can verify that your configuration worked with a few commands:</p>
- <ul>
- <li><code>ip addr</code>: make sure that there's an IP address associated with your wireless interface. That means DHCP is working.</li>
- <li><code>networkctl status</code>: make sure there's no significant errors in the logs.</li>
- </ul>
+ <p>You can verify that your configuration worked with a few commands:</p>
+ <ul>
+ <li><code><kw>ip</kw> <prop>addr</prop></code>: make sure that there's an IP address associated with your wireless interface. That means DHCP is working.</li>
+ <li><code><kw>networkctl</kw> <prop>status</prop></code>: make sure there's no significant errors in the logs.</li>
+ </ul>
- <h2>systemd-resolved</h2>
- <p>
- Now all we have left is DNS configuration, then we're done.
- This is probably the part where you can nerd out the hardest, but I try to keep it pretty minimal.
- The important parts are selecting upstream DNS servers that support secure DNS protocols (like DNS over TLS and DNSSEC) and that respect your privacy.
- For these reasons, I use <a href="https://quad9.net">quad9</a>, but do your own research and find the best upstream DNS server for you!
- Some other options include <a href="https://www.cloudflare.com/products/dns/">Cloudflare DNS</a>, <a href="https://developers.google.com/speed/public-dns/">Google's DNS</a>, or <a href="https://adguard-dns.io/en/public-dns.html">AdGuard Public DNS</a>.
- </p>
- <pre><code>{
+ <h2>systemd-resolved</h2>
+ <p>
+ Now all we have left is DNS configuration, then we're done.
+ This is probably the part where you can nerd out the hardest, but I try to keep it pretty minimal.
+ The important parts are selecting upstream DNS servers that support secure DNS protocols (like DNS over TLS and DNSSEC) and that respect your privacy.
+ For these reasons, I use <a href="https://quad9.net">quad9</a>, but do your own research and find the best upstream DNS server for you!
+ Some other options include <a href="https://www.cloudflare.com/products/dns/">Cloudflare DNS</a>, <a href="https://developers.google.com/speed/public-dns/">Google's DNS</a>, or <a href="https://adguard-dns.io/en/public-dns.html">AdGuard Public DNS</a>.
+ </p>
+ <pre><code>{
<prop>networking</prop>.<prop>nameservers</prop> = [
<str>"9.9.9.9#dns.quad9.net"</str>
<str>"149.112.112.112#dns.quad9.net"</str>
@@ -151,23 +149,25 @@
};
}</code></pre>
- <p>You can verify your DNS configuration by using the <code>resolvectl status</code> command or by just opening a website.</p>
+ <p>You can verify your DNS configuration by using the <code><kw>resolvectl</kw> <prop>status</prop></code>
+ command or by just opening a website.</p>
- <h2>P.S. Captive Portals</h2>
- <p>
- Captive portals are those wifi login pages that pop up when you connect to some public wifi networks.
- Some captive portals don't behave correctly when you're using an encrypted third-party DNS server instead of the network's advertised resolver.
- To get around this, I use <a href="https://github.com/FiloSottile/captive-browser">Captive Browser</a> (<a href="https://search.nixos.org/packages?channel=26.05&query=captive-browser#show=captive-browser">nixpkgs</a>), which launches an instance of Chromium through a SOCKS5 proxy, avoiding the system DNS configuration altogether.
- This allows you to access a captive portal for long enough to log in and gain internet access.
- Pretty neat!
- </p>
+ <h2>P.S. Captive portals</h2>
+ <p>
+ Captive portals are those wifi login pages that pop up when you connect to some public wifi networks.
+ Some captive portals don't behave correctly when you're using an encrypted third-party DNS server instead of the network's advertised resolver.
+ To get around this, I use <a href="https://github.com/FiloSottile/captive-browser">Captive Browser</a>
+ (<a href="https://search.nixos.org/packages?channel=26.05&query=captive-browser#show=captive-browser">nixpkgs</a>), which launches an instance of Chromium through a SOCKS5 proxy, avoiding the system DNS configuration altogether.
+ This allows you to access a captive portal for long enough to log in and gain internet access.
+ Pretty neat!
+ </p>
- <h2>P.P.S. I miss nm-applet</h2>
- <p>
- Probably the biggest downside to this setup is the lack of desktop integration.
- GNOME and Plasma only support NetworkManager in their network configuration menu, so you're kinda out of luck.
- For tiling window manager people, I can recommend <a href="https://github.com/e-tho/iwmenu">iwmenu</a>, which is a launcher (dmenu, rofi, fuzzel)-based menu for connecting to wifi networks via iwd.
- </p>
- </article>
-</body>
-</html> \ No newline at end of file
+ <h2>P.P.S. I miss nm-applet</h2>
+ <p>
+ Probably the biggest downside to this setup is the lack of desktop integration.
+ GNOME and Plasma only support NetworkManager in their network configuration menu, so you're kinda out of luck.
+ For tiling window manager people, I can recommend <a href="https://github.com/e-tho/iwmenu">iwmenu</a>, which is a launcher (dmenu, rofi, fuzzel)-based menu for connecting to wifi networks via iwd.
+ </p>
+ </article>
+ </body>
+</html>
diff --git a/no_ai.html b/no_ai.html
index 3a142a0..d0127b4 100644
--- a/no_ai.html
+++ b/no_ai.html
@@ -2,7 +2,6 @@
<html>
<head>
<title>Taking a break</title>
- <link rel="stylesheet" href="prose.css">
<script src="article.js"></script>
</head>
<body>
diff --git a/prose.css b/prose.css
index db54f26..3a053c5 100644
--- a/prose.css
+++ b/prose.css
@@ -1,6 +1,11 @@
-@import url('https://fonts.googleapis.com/css2?family=Gelasio:ital,wght@0,400..700;1,400..700&display=swap');
@import url('style.css');
+:root {
+ --sx: 1rem;
+ --lx: 3rem;
+ --lh: 1.5;
+}
+
article {
width: 100%;
max-width: 75ch;
@@ -11,13 +16,22 @@ article {
p {
color: #e6e6e6;
- font-family: 'Gelasio';
- line-height: 1.3;
+ font-family: var(--fontSerif);
+ line-height: var(--lh);
font-size: 1.1rem;
+ margin: var(--sx) 0;
+}
+
+sup {
+ font-size: 0.8em;
+ line-height: 0;
+ vertical-align: baseline;
+ position: relative;
+ top: -0.5em;
}
a {
- color: #4DA3FF;
+ color: #49f;
text-decoration: none;
&:hover {
@@ -27,8 +41,8 @@ a {
li {
color: #e6e6e6;
- font-family: 'Gelasio';
- line-height: 1.3;
+ font-family: var(--fontSerif);
+ line-height: var(--lh);
font-size: 1.1rem;
&::marker {
@@ -36,29 +50,12 @@ li {
}
}
-h1 {
- color: #e6e6e6;
- line-height: 1.15;
- margin-bottom: 0;
- font-family: 'Gelasio';
- font-weight: 600;
-}
-
-h2 {
- color: #e6e6e6;
- line-height: 1;
- margin-top: 3rem;
- margin-bottom: 0;
- font-family: 'Gelasio';
- font-weight: 600;
-}
-
-h3 {
+h1, h2, h3 {
color: #e6e6e6;
- line-height: 1;
- margin-top: 2rem;
- margin-bottom: 0;
- font-family: 'Gelasio';
+ margin-top: var(--lx);
+ margin-bottom: var(--sx);
+ font-family: var(--fontSerif);
+ line-height: var(--lh);
font-weight: 600;
}
@@ -71,15 +68,14 @@ hr {
height: 2px;
border: 0;
border-top: 2px solid #888;
- margin: 1em 0;
+ margin: var(--sx) 0;
padding: 0;
}
time {
display: block;
- font-family: 'Gelasio';
+ font-family: var(--fontSerif);
color: #888;
- margin-top: 0.5rem;
}
@media (max-width: 1000px) {
@@ -94,7 +90,7 @@ time {
}
details {
- font-family: 'Gelasio';
+ font-family: var(--fontSerif);
color: #888;
summary::marker {
@@ -103,13 +99,18 @@ details {
}
table {
+ --tsx_x: calc(var(--sx) / 3);
+ --tsx_y: calc(var(--sx) / 1.5);
+
+ font-family: var(--fontSerif);
+ margin: var(--sx) 0;
+
border-collapse: collapse;
- margin: 0 auto;
th {
color: #e6e6e6;
text-align: center;
border: solid;
- padding: 0 1.5ch;
+ padding: var(--tsx_x) var(--tsx_y);
border-width: 0 0 1px 0;
&[scope="row"] {
@@ -117,40 +118,94 @@ table {
}
}
td {
- color: #00ff78;
+ color: #6e7;
text-align: center;
- padding: 0 1.5ch;
+ padding: var(--tsx_x) var(--tsx_y);
}
}
-code .path {
- color: #888;
+math {
+ font-family: var(--fontMath);
+ font-size: 1.2rem;
+ transform: translateZ(0);
+
+ msub > :nth-child(2) {
+ transform: translateY(-0.2em);
+ font-size: 0.8rem;
+ }
}
-/* inline code */
+/* CODEBLOCKS */
code {
- color: #00ff78;
- font-family: 'Roboto Mono';
+ font-size: 0.95rem;
+ color: #e6e6e6;
+ white-space: pre;
+ font-family: 'Fira Code', monospace;
+
+ kw { color: #49f; }
+ ty { color: #4d9; }
+ fn { color: #7bf; }
+ mac { color: #d69; }
+ str { color: #6e7; }
+ num { color: #9c9; }
+ com { color: #888; }
+ prop { color: #8cf; }
+ mod { color: #bcd; }
+ id { color: inherit; }
}
-/* CODEBLOCKS */
pre {
- color: #00ff78;
- font-family: 'Roboto Mono';
+ max-width: 100%;
+ overflow-x: auto;
+ overflow-y: hidden;
+ box-sizing: border-box;
- code {
- color: #e6e6e6;
+ margin: var(--sx) 0;
+ line-height: var(--lh);
+}
+
+/* HEADER */
+header {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr);
+ grid-template-rows: auto auto;
+ gap: var(--sx);
+
+ .header-logo-link {
+ display: block;
+ height: 100%;
+ aspect-ratio: 1;
+
+ background-color: #e6e6e6;
+
+ mask-image: url("/Logo.svg");
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ mask-position: center;
}
- kw { color: #6cb8ff; } /* keywords */
- ty { color: #4ec9b0; } /* types */
- fn { color: #dcdcaa; } /* functions */
- mac { color: #c586c0; } /* macros */
- str { color: #ce9178; } /* strings */
- num { color: #b5cea8; } /* numbers */
- com { color: #7f848e; font-style: italic; }
- prop { color: #9cdcfe; } /* fields */
- mod { color: #e6e6e6; } /* modules */
- id { color: inherit; } /* local variables */
-}
+ .header-logo-link:hover {
+ background-color: #49f;
+ }
+
+ .header-info {
+ min-width: 0;
+ align-self: center;
+ h1 {
+ line-height: 1;
+ margin: 0;
+ }
+ }
+
+ time {
+ line-height: var(--lh);
+ margin: 0;
+ }
+
+ hr {
+ margin: 0;
+ grid-column: 1 / -1;
+ width: 100%;
+ }
+} \ No newline at end of file
diff --git a/reversible.html b/reversible.html
index 378045f..24b5b87 100644
--- a/reversible.html
+++ b/reversible.html
@@ -2,11 +2,8 @@
<html>
<head>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
-
<title>Reversible Programming Blew my Mind (Reversible Part 1)</title>
<meta property="article:published_time" content="2026-07-05">
- <link rel="stylesheet" href="prose.css">
<script src="./article.js"></script>
</head>
@@ -24,18 +21,21 @@
<div id="toc"></div>
<h2 id="math">Math basis</h2>
- <p>So remember in math class when you learned to take the inverse of a function?</p>
- <p>For example, say you have <code>y = 3*x + 6</code>.</p>
- <p>You can take the inverse by solving for x. In this case, the inverse of our function is <code>x = y/3 - 2</code>.</p>
- <p>The idea behind reversible programming is that there's a specific way to write your code such that it can <strong>automatically compute the inverse</strong>.</p>
+ <p>
+ So remember in math class when you learned to take the inverse of a function?
+ For example, say you have <code>y = 3*x + 6</code>.
+ You can take the inverse by solving for <code>x</code>.
+ In this case, the inverse of our function is <code>x = y/3 - 2</code>.
+ The idea behind reversible programming is that there's a specific way to write your code such that it can <strong>automatically compute the inverse</strong>.
+ </p>
<p>This has some wild implications:</p>
<ul>
<li>Writing a parser automatically gives you a pretty-printer implementation</li>
- <li>Database migrations are only <em>half</em> as scary (writing your <code>up</code> script automatically gives you your <code>down</code> script)</li>
+ <li>Database migrations are only <em>half</em> as scary (writing your <code><fn>up</fn></code> script automatically gives you your <code><fn>down</fn></code> script)</li>
<li>Writing operations on an image (ex. Photoshop clone) gives you free undo and redo.</li>
</ul>
<p>
- These are just a few of the crazy things you could <em>theoretically</em> do with Reversible Programming.
+ These are just a few of the crazy things you could <em>theoretically</em> do with reversible programming.
But how does it actually work?
</p>
@@ -58,7 +58,7 @@
<p>
As a nice starter, let's write a block that would compute addition.
- We can model this with a struct and an impl of the <code>Rev</code> trait.
+ We can model this with a struct and an impl of the <code><ty>Rev</ty></code> trait.
</p>
<pre><code><kw>struct</kw> <ty>Addition</ty>&lt;<ty>A</ty>&gt; {
<prop>amount</prop>: <ty>A</ty>
@@ -84,7 +84,7 @@
<p>
While the generics might look scary, this is just saying "the input and output can be any type that you can add and subtract with."
- Honestly these are light work compared to what's coming up.
+ <span class="comment">Honestly these are light work compared to what's coming up.</span>
</p>
<p>Oh, and it will look nicer if we have an easy way to construct an <code>Addition</code> block:</p>
<pre><code><kw>fn</kw> <fn>plus</fn>&lt;<ty>A</ty>&gt;(<id>amount</id>: <ty>A</ty>) -&gt; <ty>Addition</ty>&lt;<ty>A</ty>&gt; {
@@ -95,7 +95,7 @@
<pre><code class="language-rust"><kw>fn</kw> <fn>main</fn>() {
<kw>let</kw> <id>operation</id> = <fn>plus</fn>(<num>5</num>);
- <mac>println!</mac>(<str>"{}"</str>, <id>operation</id>.<fn>forward</fn>(<num>6</num>)); <com>// prints 11 (6 + 5 = 11)</com>
+ <mac>println!</mac>(<str>"{}"</str>, <id>operation</id>.<fn>forward</fn>(<num>6</num>)); <com>// prints 11 (6 + 5 = 11)</com>
<mac>println!</mac>(<str>"{}"</str>, <id>operation</id>.<fn>reverse</fn>(<num>11</num>)); <com>// prints 6 (11 - 5 = 6)</com>
}</code></pre>
@@ -103,14 +103,14 @@
trait impl said.</p>
<p>I've implemented a few more in the <a href="./reversible.rs#:~:text=%2F%2F%20more%20blocks">source code</a>:</p>
<ul>
- <li><code>neg()</code> negates a number</li>
- <li><code>times(x)</code> multiplies a number by x</li>
- <li><code>discrete(x: Vec&lt;(A, B)&gt;)</code> creates a reversible block out of a set of discrete inputs and outputs.</li>
+ <li><code><fn>neg</fn>()</code> negates a number</li>
+ <li><code><fn>times</fn>(x)</code> multiplies a number by x</li>
+ <li><code><fn>discrete</fn>(x: <ty>Vec</ty>&lt;(<ty>A</ty>, <ty>B</ty>)&gt;)</code> creates a reversible block out of a set of discrete inputs and outputs.</li>
</ul>
<h2 id="first">First Combinators</h2>
<p>
- The first combinator we'll implement is <code>Pipe</code>.
+ The first combinator we'll implement is <code><ty>Pipe</ty></code>.
This takes in two <code>Rev</code>s and and makes one that applies them in sequential order.
</p>
<pre><code><kw>struct</kw> <ty>Pipe</ty>&lt;<ty>X</ty>, <ty>Y</ty>&gt;(<ty>X</ty>, <ty>Y</ty>);
@@ -132,7 +132,7 @@
}</code></pre>
<p>
- Additionally, we'll implement <code>Inverse</code> (not to be confused with <code>.reverse()</code>).
+ Additionally, we'll implement <code><ty>Inverse</ty></code> (not to be confused with <code>.<fn>reverse</fn>()</code>).
This flips the forward and reverse methods.
</p>
<pre><code><kw>struct</kw> <ty>Inverse</ty>&lt;<ty>X</ty>&gt;(<ty>X</ty>);
@@ -194,7 +194,7 @@
<h2 id="under">Under</h2>
<p>
- <code>under</code> is a higher order combinator, which means it's implemented in terms of other combinators.
+ <code><fn>under</fn></code> is a higher order combinator, which means it's implemented in terms of other combinators.
Under basically says "do a thing, do another thing, then undo the first thing.
With this foundation built up, we can implement it quite easily:
</p>
diff --git a/soplt.html b/soplt.html
index a80c81e..60ba75b 100644
--- a/soplt.html
+++ b/soplt.html
@@ -3,7 +3,6 @@
<head>
<title>Summer of PLT</title>
<meta property="article:published_time" content="2026-05-10">
- <link rel="stylesheet" href="prose.css">
<script src="article.js"></script>
</head>
<body>
diff --git a/style.css b/style.css
index 19c33e7..23162b3 100644
--- a/style.css
+++ b/style.css
@@ -1,4 +1,4 @@
-@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap');
+@import url('fonts.css');
*, *::before, *::after {
box-sizing: border-box;