<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Light Through the Mirror — Signal</title>
    <link>https://light-through-the-mirror.com/signal/</link>
    <atom:link href="https://light-through-the-mirror.com/signal/feed.xml" rel="self" type="application/rss+xml"/>
    <description>Notes on making things with computers.</description>
    <language>en</language>
    <item>
      <title>Deterministic colour</title>
      <link>https://light-through-the-mirror.com/signal/deterministic-colour/</link>
      <guid isPermaLink="true">https://light-through-the-mirror.com/signal/deterministic-colour/</guid>
      <pubDate>Sat, 30 May 2026 12:00:00 GMT</pubDate>
      <description>How this site derives every colour it shows from six numbers and a hash.</description>
      <content:encoded><![CDATA[<p>This site has no colour picker anywhere in its history. Every surface you see
is computed: six hues chosen in OKLCH, one lightness, one chroma, and a hash
function. This post is about why that constraint exists and what it bought.</p>
<p>(OKLCH is the cylindrical form of OKLab — lightness, chroma, hue —
designed so that equal numeric steps look like equal visual steps.)</p>
<p>The problem with picking colours by eye is not taste; it's <em>fairness</em>. This
site is six sections that must feel like siblings — same lightness, same
saturation, different hue — and human eyes are famously bad judges of that.
A yellow and a blue with the same HSL "lightness" are nowhere near equally
light. OKLCH fixes the yardstick: <code>oklch(0.88 0.055 h)</code> is perceptually the
same pastel whatever you substitute for <code>h</code>, which is the whole mirror idea
in one line of CSS.</p>
<p>Posts go one step further. Each post's surface drifts from its section's base
by a few degrees of hue and a few hundredths of lightness — enough to feel,
too little to name — and the drift is a pure function of the slug:</p>
<pre><code class="language-ts">export function shadeFor(section: SectionKey, slug = '') {
  const base = SECTIONS[section].hue;
  const h = hash(slug); // FNV-1a — stable forever, everywhere
  return {
    hue: base + ((h &#x26; 0xff) / 255 - 0.5) * 16, // ±8°
    L: BASE.L + (((h >> 8) &#x26; 0xff) / 255 - 0.5) * 0.06, // ±0.03
    C: BASE.C + (((h >> 16) &#x26; 0xff) / 255 - 0.5) * 0.03, // ±0.015
  };
}
</code></pre>
<p>Try it — this widget runs the real function, live:</p>
<p>Deterministic means <em>accountable</em>. The same post is the same colour forever,
on every build, on every machine. No database row stores it; no human
maintains it. And because the palette is a function, it can be tested like
one — the build runs every derivable shade against WCAG contrast thresholds
and refuses to ship if a single combination fails. Taste gets you a nice
palette; a build gate keeps it nice.</p>
<p>The full derivation lives in the colophon, because on a site about a mirror,
showing your work is the brand.</p>]]></content:encoded>
    </item>
    <item>
      <title>Static sites forever</title>
      <link>https://light-through-the-mirror.com/signal/static-sites-forever/</link>
      <guid isPermaLink="true">https://light-through-the-mirror.com/signal/static-sites-forever/</guid>
      <pubDate>Mon, 05 Jan 2026 12:00:00 GMT</pubDate>
      <description>The case for a personal site that is just files, and will still be files in twenty years.</description>
      <content:encoded><![CDATA[<p>Every page of this site is a file. Not a route resolved by a process, not a
row hydrated by a runtime — a file, sitting in a directory, sent to you by
the dumbest possible server doing the thing servers have done since 1991.
This is a deliberate bet about time, and I want to write it down.</p>
<p>Personal sites die of dependency, not of neglect. The essay from 2009 is
fine; the CMS under it is not. The database needs a version of PHP that
needs a version of a server that nobody rents anymore. Every moving part is
a clock counting down to a weekend of migration — and eventually one
migration doesn't happen, and eleven years of writing 404s into the fog.</p>
<p>A directory of HTML has no clock, or almost none. Its dependencies are the
browser and the filesystem — the two most backward-compatible artifacts in
computing. It can move hosts with <code>rsync</code>. It can be archived by anyone with
<code>wget</code>, including future me, including the Internet Archive, including a
grandchild with a USB stick. Longevity is mostly the art of having fewer
dependencies than the things trying to kill you.</p>
<p>The build can be as modern as it likes — this one runs a component framework,
a typed content pipeline, and a contrast-checking gate — because the build
happens <em>once, on my machine</em>, where complexity is cheap and reversible. What
leaves the machine is inert. The reader pays no tax on my tooling: an article
here is readable with JavaScript disabled, because the JavaScript is
decoration, not load-bearing wall.</p>
<p>There are honest costs — no comments without a third party, search done ahead
of time, anything "live" fenced off — and this site accepts every one of
them. They are the membership fee of the only club that interests me: sites
that will still open.</p>]]></content:encoded>
    </item>
    <item>
      <title>Signal to noise</title>
      <link>https://light-through-the-mirror.com/signal/signal-to-noise/</link>
      <guid isPermaLink="true">https://light-through-the-mirror.com/signal/signal-to-noise/</guid>
      <pubDate>Tue, 25 Nov 2025 12:00:00 GMT</pubDate>
      <description>Notes on unsubscribing from the feed and re-subscribing to people.</description>
      <content:encoded><![CDATA[<p>I stopped reading feeds ranked by machines about a year ago, and the
withdrawal was real and embarrassing: two weeks of reaching for a phantom
limb that dispensed novelty. Then something older grew back in its place —
an actual sense of <em>who</em> I read, rather than <em>what</em> I had been fed.</p>
<p>The mechanism matters. A ranked feed optimises for the marginal second of
your attention, which means it optimises for whatever bypasses judgement.
A chronological subscription — RSS, a newsletter, a friend's site checked on
Sunday — optimises for nothing at all. It just delivers, in order, what
someone chose to publish. The choosing is the signal. Everything a ranking
adds is, definitionally, noise: it is the difference between what your
people said and what a system predicts you'll react to.</p>
<p>(This site ships full-text RSS per section, plus a combined feed —
built in the standard-pages phase — precisely because of this post.)</p>
<p>The practical setup is almost insultingly simple. A feed reader with maybe
thirty subscriptions, weeded seasonally like a garden. No unread counts —
that number is the ranking sneaking back in through the window. Sunday
morning, coffee, read what's there, done. Some weeks that's forty minutes;
some weeks it's five, because my thirty people had quiet weeks, and a system
that can be <em>quiet</em> is precisely the point.</p>
<p>What I lost is real: serendipity at scale, the occasional gem from nowhere.
What I got back is a reading life with a shape — authors whose thinking I can
watch develop across months, disagreements that stay in context, and the
restful knowledge that when there is nothing new, nothing pretends to be.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
