<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Toms Zvirbulis: writing</title><description>Notes and essays on building software.</description><link>https://tomszir.com</link><item><title>How this site is built</title><link>https://tomszir.com/writing/how-this-site-is-built</link><guid isPermaLink="true">https://tomszir.com/writing/how-this-site-is-built</guid><description>The stack behind tomszir.com, why each piece is there, and the 14 KB budget it has to fit in.</description><pubDate>Fri, 30 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I wanted a personal site that shows I understand what I’m doing, not another generic portfolio. This is it: eight pages of HTML, one stylesheet and one script file. Nothing runs on a server when you load it. I wanted most of the work to happen at build time, and I wanted the build to check its own output before anything is deployed.&lt;/p&gt;
&lt;h2 id=&quot;a-static-site-on-purpose&quot;&gt;A static site, on purpose&lt;/h2&gt;
&lt;p&gt;I built it with Astro 7.4.4, and the output is plain static files. There’s no server rendering, no database and no API. The pages only change when I write something, which is a few times a month at best. Rendering them per request would just add a server to keep alive and a cold start to wait for.&lt;/p&gt;
&lt;p&gt;Astro treats JavaScript as opt-in, which is what I wanted. A component renders to HTML when the site builds, and nothing ships to the browser unless I write a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; for it. The home page loads seven files on a first visit: the HTML, one stylesheet, one script of 1.1 KB compressed, and four small font files.&lt;/p&gt;
&lt;aside class=&quot;decision&quot; aria-label=&quot;Decision&quot; data-astro-cid-ffatqjay&gt;&lt;span class=&quot;label&quot; data-astro-cid-ffatqjay&gt;Decision&lt;/span&gt;&lt;span class=&quot;chosen&quot; data-astro-cid-ffatqjay&gt;Cross-document view transitions in CSS&lt;/span&gt;&lt;span class=&quot;label&quot; data-astro-cid-ffatqjay&gt;Instead of&lt;/span&gt;&lt;span data-astro-cid-ffatqjay&gt;Astro&amp;#39;s ClientRouter, which turns the site into a single-page app&lt;/span&gt;&lt;span class=&quot;label&quot; data-astro-cid-ffatqjay&gt;Because&lt;/span&gt;&lt;span data-astro-cid-ffatqjay&gt;&lt;p&gt;I didn’t want to ship a router to every page to animate between eight of them, and every inline
script would need care to rerun after navigation. &lt;code&gt;@view-transition&lt;/code&gt; gives the page-to-page animation
from real page loads in browsers that support it. In the others, links navigate without it.&lt;/p&gt;&lt;/span&gt;&lt;/aside&gt;
&lt;p&gt;So the whole router is three lines of CSS, behind the reduced-motion preference:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;media&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;prefers-reduced-motion&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; no-preference&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;view-transition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;    navigation&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; auto&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;hosting-static-assets-on-cloudflare-workers&quot;&gt;Hosting: static assets on Cloudflare Workers&lt;/h2&gt;
&lt;p&gt;My domain was already on Cloudflare, so the files go to Workers static assets. There’s no Worker script at all, just a &lt;code&gt;dist/&lt;/code&gt; folder and this config. Cloudflare builds and deploys every push to &lt;code&gt;main&lt;/code&gt; on its own, so deploying is &lt;code&gt;git push&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsonc&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;quot;tomszir-com&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;assets&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;directory&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;quot;./dist&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;not_found_handling&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;quot;404-page&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;html_handling&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;quot;drop-trailing-slash&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Astro writes each page as a file (&lt;code&gt;/cv&lt;/code&gt; is &lt;code&gt;cv.html&lt;/code&gt;) and Workers serves it without the extension. Unknown paths get the real 404 page with a 404 status. A &lt;code&gt;_headers&lt;/code&gt; file in &lt;code&gt;public/&lt;/code&gt; caches the hashed files under &lt;code&gt;/_astro/&lt;/code&gt; for a year as immutable, since their names change whenever their content does:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/_astro/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Cache-Control: public, max-age=31536000, immutable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I didn’t use the Astro Cloudflare adapter. It’s for on-demand rendering, and this site doesn’t do any.&lt;/p&gt;
&lt;h2 id=&quot;the-14-kb-budget&quot;&gt;The 14 KB budget&lt;/h2&gt;
&lt;p&gt;TCP starts a new connection with a congestion window of ten segments. That works out to about 14 KB before the server has to wait for an acknowledgement. TLS and HTTP/3 change the details, so it’s a rule of thumb, not a guarantee.&lt;/p&gt;
&lt;p&gt;The home page’s HTML is 6.9 KB compressed, so it arrives in that first window. The stylesheet and script follow in one more round trip, in parallel. I applied the rule of thumb to all three: 14 KB compressed for the HTML, CSS and JavaScript, fonts aside.&lt;/p&gt;
&lt;p&gt;The home page currently weighs 11.7 KB. Two scripts measure it again after every build:&lt;/p&gt;
&lt;figure class=&quot;flow&quot; data-astro-cid-nf3vu25q&gt;&lt;ol class=&quot;track&quot; data-astro-cid-nf3vu25q&gt;&lt;li class=&quot;item&quot; data-astro-cid-nf3vu25q&gt;&lt;div class=&quot;step&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;number meta muted&quot; data-astro-cid-nf3vu25q&gt;01&lt;/span&gt;&lt;span class=&quot;body&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;title&quot; data-astro-cid-nf3vu25q&gt;astro build&lt;/span&gt;&lt;span class=&quot;note&quot; data-astro-cid-nf3vu25q&gt;Renders the pages, bundles the styles and downloads the fonts into dist/.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class=&quot;item&quot; data-astro-cid-nf3vu25q&gt;&lt;div class=&quot;connector meta muted&quot; aria-hidden=&quot;true&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;arrow&quot; data-astro-cid-nf3vu25q&gt;↓&lt;/span&gt;&lt;span data-astro-cid-nf3vu25q&gt;dist/&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;step focus&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;number meta muted&quot; data-astro-cid-nf3vu25q&gt;02&lt;span class=&quot;square&quot; aria-hidden=&quot;true&quot; data-astro-cid-nf3vu25q&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;body&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;title&quot; data-astro-cid-nf3vu25q&gt;stamp-build&lt;/span&gt;&lt;span class=&quot;note&quot; data-astro-cid-nf3vu25q&gt;Measures each page compressed and writes the size, date and commit in.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class=&quot;item&quot; data-astro-cid-nf3vu25q&gt;&lt;div class=&quot;connector meta muted&quot; aria-hidden=&quot;true&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;arrow&quot; data-astro-cid-nf3vu25q&gt;↓&lt;/span&gt;&lt;span data-astro-cid-nf3vu25q&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;number meta muted&quot; data-astro-cid-nf3vu25q&gt;03&lt;/span&gt;&lt;span class=&quot;body&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;title&quot; data-astro-cid-nf3vu25q&gt;check-dist&lt;/span&gt;&lt;span class=&quot;note&quot; data-astro-cid-nf3vu25q&gt;Fails the build if a page breaks a rule or the home page passes 14 KB.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class=&quot;item&quot; data-astro-cid-nf3vu25q&gt;&lt;div class=&quot;connector meta muted&quot; aria-hidden=&quot;true&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;arrow&quot; data-astro-cid-nf3vu25q&gt;↓&lt;/span&gt;&lt;span data-astro-cid-nf3vu25q&gt;only if every check passes&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;number meta muted&quot; data-astro-cid-nf3vu25q&gt;04&lt;/span&gt;&lt;span class=&quot;body&quot; data-astro-cid-nf3vu25q&gt;&lt;span class=&quot;title&quot; data-astro-cid-nf3vu25q&gt;Cloudflare deploy&lt;/span&gt;&lt;span class=&quot;note&quot; data-astro-cid-nf3vu25q&gt;Uploads dist/ as static assets on every push to main. No Worker script.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;figcaption class=&quot;meta muted&quot; data-astro-cid-nf3vu25q&gt;What runs on every build, and on every push.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;stamp-build&lt;/code&gt; gzips each page together with the stylesheet and script it loads, then writes the size into the page, along with the build date and the commit. That’s where the numbers in the footer come from. Browsers that support Brotli get something smaller, so gzip is the safe number to measure.&lt;/p&gt;
&lt;p&gt;Writing the size into the page also changes the page’s size, which I found out the hard way: the first version of the stamp printed 10.9 KB on a page that weighed 10.8. That’s where the second pass came from. The first pass writes a size, the second measures again with it in place and settles it:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; pass &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; pass &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; pass&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;++)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; kb &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;pageBytes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 1024&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;toFixed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; percent &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;kb&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; BUDGET_KB&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;toFixed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  html &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt; fill&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;page-kb&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; kb&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;    /&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;data-build-fill&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;[^&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;]*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;style=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;--fill:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;\s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;*)[^&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;]*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;    `$1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;percent&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;%`&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;check-dist&lt;/code&gt; then reads every page in &lt;code&gt;dist/&lt;/code&gt; and fails the build when any of these happen. It’s part of &lt;code&gt;pnpm build&lt;/code&gt;, so a failing check stops Cloudflare’s build too, and the broken version never goes live:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a page has no &lt;code&gt;lang&lt;/code&gt;, no title, no description, or more than one &lt;code&gt;h1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;anything loads from another origin&lt;/li&gt;
&lt;li&gt;the home page goes over 14 KB&lt;/li&gt;
&lt;li&gt;a printed size is more than 0.1 KB off the real one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last rule is how the first bug showed up.&lt;/p&gt;
&lt;h2 id=&quot;fonts-without-a-third-party&quot;&gt;Fonts without a third party&lt;/h2&gt;
&lt;p&gt;The site uses Inter Tight and JetBrains Mono. A Google Fonts &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; would be a request to another company on every page view, and I didn’t want that, so the fonts live in the repository. They come from the Fontsource packages, pinned by version and checksum in &lt;code&gt;vendor/fonts.lock.json&lt;/code&gt;, and &lt;code&gt;mise run fonts:vendor&lt;/code&gt; downloads them and cuts each family down to the characters the site actually uses. Each family becomes two files: one with ASCII and a handful of symbols (arrows, quotes, dashes), one with the Latvian letters. That took the fonts from 75 KB to 48 KB.&lt;/p&gt;
&lt;p&gt;Astro’s font API serves them from the site and sizes the fallback fonts to match, so the page doesn’t jump when the real ones arrive. Each family is one entry in &lt;code&gt;astro.config.mjs&lt;/code&gt;, with a variant per file:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt; variants&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;family&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; weight&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  Object&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;entries&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;subsets&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(([&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;subset&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; text&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    src&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;`./src/fonts/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;family&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;subset&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;.woff2`&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;    weight&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    style&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    unicodeRange&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt; unicodeRange&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  }))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  provider&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; fontProviders&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;Inter Tight&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  cssVariable&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;--font-sans&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  fallbacks&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;&amp;#39;system-ui&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;sans-serif&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; variants&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt; variants&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;&amp;#39;inter-tight&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;400 600&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The vendoring script and the config read the same character sets, so the files and their &lt;code&gt;unicode-range&lt;/code&gt; can’t disagree. A character that isn’t in them falls back to the system font, one character at a time, instead of breaking the line. With fonts, a first visit to the home page is about 60 KB in seven requests.&lt;/p&gt;
&lt;h2 id=&quot;javascript-only-where-it-earns-it&quot;&gt;JavaScript only where it earns it&lt;/h2&gt;
&lt;p&gt;Every page works with JavaScript off. The scripts only add to a page that’s already complete:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A theme script inlined in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, so a stored or system dark theme is applied before the first paint instead of flashing light. Without JavaScript the site follows the system theme.&lt;/li&gt;
&lt;li&gt;The theme toggle, which uses &lt;code&gt;document.startViewTransition&lt;/code&gt; to reveal the new theme from the button. Without JavaScript there’s no toggle.&lt;/li&gt;
&lt;li&gt;A clock and the sun’s elevation over Riga, computed in the browser from the date. Without JavaScript the panel says Latvia.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The theme switch was out of sync at first. The new theme is revealed as a growing circle, but every element with a colour transition kept fading at its own speed inside it, and the elements with view-transition names were animated separately, outside the circle. That’s where this rule came from. While the switch runs, both are turned off:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F5482;--shiki-dark:#A9BCD6&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;data-theme-switching&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F5482;--shiki-dark:#A9BCD6&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;data-theme-switching&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F5482;--shiki-dark:#A9BCD6&quot;&gt;before&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F5482;--shiki-dark:#A9BCD6&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;data-theme-switching&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F5482;--shiki-dark:#A9BCD6&quot;&gt;after&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; none&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt; !important&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  view-transition-name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; none&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt; !important&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The sun’s elevation is the standard low-precision solar position, good to about a degree, in 18 lines:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt; sunElevation&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F5482;--shiki-dark:#A9BCD6&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F5482;--shiki-dark:#A9BCD6&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; days &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; date&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;getTime&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 86_400_000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 10_957.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; anomaly &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;357.529&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 0.98560028&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; days&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; RAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; meanLongitude &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 280.459&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 0.98564736&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; days&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; longitude &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;meanLongitude &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 1.915&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;sin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;anomaly&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 0.02&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;sin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; anomaly&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; RAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; obliquity &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;23.439&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 0.00000036&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; days&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; RAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; rightAscension &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;atan2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;cos&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;obliquity&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;sin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;longitude&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;),&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;cos&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;longitude&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; declination &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;asin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;sin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;obliquity&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;sin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;longitude&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; siderealHours &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;18.697374558&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 24.06570982441908&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; days&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; hourAngle &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;siderealHours &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 15&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; LONGITUDE&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; RAD &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; rightAscension&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; latitude &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; LATITUDE &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; RAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;    Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;asin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;      Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;sin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;latitude&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;sin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;declination&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; +&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;        Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;cos&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;latitude&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;cos&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;declination&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;cos&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;hourAngle&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;    )&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; RAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These, and a few smaller ones, are small enough that Astro inlines them into the page: 5.8 KB in all, 2.2 KB compressed, counted inside the 11.7 KB. The one script file is Astro’s link prefetching, 2.4 KB and 1.1 KB compressed. It fetches a page when you hover or touch a link to it.&lt;/p&gt;
&lt;h2 id=&quot;content-as-data&quot;&gt;Content as data&lt;/h2&gt;
&lt;p&gt;Posts and product pages are Markdown and MDX files with frontmatter checked against Zod schemas, so a post with a missing date doesn’t build. The schema for posts, in &lt;code&gt;src/content.config.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; writing &lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt; defineCollection&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;  loader&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt; glob&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt; base&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;./src/content/writing&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt; pattern&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;**/*.{md,mdx}&amp;#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt; }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;  schema&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    title&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    description&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    published&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;coerce&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    updated&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;coerce&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;    draft&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; z&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#F2F1EC&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;  }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The decision blocks and the diagram in this post are components, imported at the top of the file. This is how the post starts, and how the Biome decision below is written:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;mdx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; How this site is built&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; The stack behind tomszir.com, why each piece is there, and the 14 KB budget it has to fit in.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;published&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; 2026-10-30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt; Decision &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;#39;../../components/write-up/Decision.astro&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;Decision&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; chosen&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;&amp;quot;Biome for linting and formatting&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; instead&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt;&amp;quot;ESLint and Prettier&amp;quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3&quot;&gt;  One tool, one config file and one fast binary for TypeScript, CSS, JSON and Markdown.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B53A0A;--shiki-dark:#FF7A47&quot;&gt;Decision&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;tooling-pinned&quot;&gt;Tooling, pinned&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mise&lt;/code&gt; pins Node 24 and pnpm 12.16.1, so the toolchain is the same on any machine that runs &lt;code&gt;mise install&lt;/code&gt;. Every dependency is an exact version, and pnpm runs install scripts for only two packages, esbuild and workerd. Both rules live in &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes instrument-light instrument-dark&quot; style=&quot;--shiki-light:#121212;--shiki-dark:#E9E8E3;--shiki-light-bg:#EEEEEA;--shiki-dark-bg:#141413;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;savePrefix&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A5622;--shiki-dark:#D9C9A0&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;allowBuilds&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;  esbuild&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#33332F;--shiki-dark:#CFCDC5&quot;&gt;  workerd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F5F5B;--shiki-dark:#8F8E88&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#9A3F10;--shiki-dark:#F0A274&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TypeScript is at 6.0.3, not 7, because &lt;code&gt;@astrojs/check&lt;/code&gt; doesn’t support 7 yet. One command, &lt;code&gt;mise run check&lt;/code&gt;, runs the type check, Biome, the build, the stamp and &lt;code&gt;check-dist&lt;/code&gt;. Nothing counts as done until it passes.&lt;/p&gt;
&lt;aside class=&quot;decision&quot; aria-label=&quot;Decision&quot; data-astro-cid-ffatqjay&gt;&lt;span class=&quot;label&quot; data-astro-cid-ffatqjay&gt;Decision&lt;/span&gt;&lt;span class=&quot;chosen&quot; data-astro-cid-ffatqjay&gt;Biome for linting and formatting&lt;/span&gt;&lt;span class=&quot;label&quot; data-astro-cid-ffatqjay&gt;Instead of&lt;/span&gt;&lt;span data-astro-cid-ffatqjay&gt;ESLint and Prettier&lt;/span&gt;&lt;span class=&quot;label&quot; data-astro-cid-ffatqjay&gt;Because&lt;/span&gt;&lt;span data-astro-cid-ffatqjay&gt;&lt;p&gt;One tool, one config file and one fast binary for TypeScript, CSS, JSON and Markdown. It can’t
see inside Astro templates, so two of its rules are off for &lt;code&gt;.astro&lt;/code&gt; files.&lt;/p&gt;&lt;/span&gt;&lt;/aside&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;
&lt;p&gt;The site is ready for writing. The next posts are about the two projects I’m building alongside my work.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tomszir.com/building/zvirb&quot;&gt;Zvirb&lt;/a&gt; is a self-hosted game server panel. I’m working toward a first release where one compose file gives you a running Minecraft server. Support for each game is a WebAssembly plugin, and a plugin registry is planned to install them from. The host runs every call to a plugin under a deadline and a memory budget. That sandbox is the first thing I want to write about.&lt;/p&gt;
&lt;p&gt;Seams is newer. It’s one shared, pannable quilt: people claim a few cells and write a small Canvas program for them. Every visible cell animates live, and neighbouring cells can talk across their shared edges.&lt;/p&gt;
&lt;p&gt;The backend is Rust with axum and Postgres. The grid logic is one Rust crate, compiled to native code and to WebAssembly. The quilt itself is a hand-written WebGL2 renderer, with budgets of its own: 60 fps with 64 live cells on screen, and under 150 KB of JavaScript, gzipped, for the first view. The renderer works. Next is running other people’s code safely, in sandboxed cross-origin iframes with CPU, memory and frame-time limits.&lt;/p&gt;
&lt;p&gt;None of it is finished, and this site won’t be either. It’s the place I’ll write about both as they get there.&lt;/p&gt;</content:encoded></item></channel></rss>