<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>Static.Quest</title>
	<subtitle>An dynamic webring</subtitle>
	
	<link href="https://static.quest/feed/feed.xml" rel="self"/>
	<link href="https://static.quest/"/>
	<updated>2026-08-24T00:00:00Z</updated>
	<id>https://static.quest/</id>
	<author>
		<name>Clayton Errington</name>
		<email>me@claytonerrington.com</email>
	</author>
	
	<entry>
		<title>Improving the webring links, one build at a time</title>
		<link href="https://static.quest/posts/improving-the-webring-links/"/>
		<updated>2026-08-24T13:28:30Z</updated>
		<id>https://static.quest/posts/improving-the-webring-links/</id>
		<content type="html">&lt;p&gt;If you have ever clicked the little ← and → arrows on a member&#39;s site, you have used the plumbing that ties &lt;a href=&quot;https://static.quest/&quot;&gt;Static.Quest&lt;/a&gt; together. Those links are how a web ring works: every site points to the next and previous member, and visitors can walk the whole circle without ever visiting the hub. This post is a look at how those links worked until recently, what was wrong with them, and how we made them better while staying 100% static.&lt;/p&gt;
&lt;h2 id=&quot;how-it-used-to-work&quot; tabindex=&quot;-1&quot;&gt;How it used to work &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/improving-the-webring-links/#how-it-used-to-work&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The original approach leaned on the browser. Members embedded links like this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://static.quest/next/?host=yourwebsite.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;&amp;#8594;&quot;&gt;&amp;amp;#8594;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When someone clicked that link, they landed on a small page on Static.Quest whose only job was to run some JavaScript:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read the &lt;code&gt;host&lt;/code&gt; value out of the query string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch()&lt;/code&gt; a JSON file listing all the members&lt;/li&gt;
&lt;li&gt;Find the current host in the array&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;window.location&lt;/code&gt; to the neighbor&#39;s URL&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It worked, and honestly it worked fine for years. But it had a few rough edges worth fixing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JavaScript required.&lt;/strong&gt; No JS, no redirect. You got a polite &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; message instead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An extra round trip.&lt;/strong&gt; Every hop waited on fetching and parsing &lt;code&gt;members.json&lt;/code&gt; before anything happened.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Silent failure modes.&lt;/strong&gt; Visit &lt;code&gt;/next/&lt;/code&gt; without a &lt;code&gt;?host=&lt;/code&gt; parameter and nothing happens at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ring order wasn&#39;t stable.&lt;/strong&gt; The JSON array was generated in whatever order Eleventy happened to collect the files, which is not guaranteed to be identical between machines or CI checkouts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-new-way-generate-the-redirects-at-build-time&quot; tabindex=&quot;-1&quot;&gt;The new way: generate the redirects at build time &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/improving-the-webring-links/#the-new-way-generate-the-redirects-at-build-time&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The key realization is that Eleventy already knows everything needed at build time. It has the full member list, so it knows exactly who comes before and after you in the ring. So why involve the browser at all?&lt;/p&gt;
&lt;p&gt;Instead of one generic redirect page, we now generate &lt;strong&gt;one tiny HTML page per member per direction&lt;/strong&gt; during the build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/next/yourwebsite.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/previous/yourwebsite.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each page is just a meta refresh pointing at the correct neighbor:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;en&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;UTF-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;http-equiv&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;refresh&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0; url=https://yourwebsite.com/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Walking the Static.Quest web ring to
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://yourwebsite.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;https://yourwebsite.com&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;hellip;&quot;&gt;&amp;amp;hellip;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Members embed a link to their own page (&lt;code&gt;/next/yourwebsite.com&lt;/code&gt;) rather than passing themselves as a query parameter. That URL never changes. When a new site joins the ring, the build regenerates everyone&#39;s pages, and all the neighbors quietly shift over without any member touching their markup.&lt;/p&gt;
&lt;h2 id=&quot;how-it-is-built&quot; tabindex=&quot;-1&quot;&gt;How it is built &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/improving-the-webring-links/#how-it-is-built&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Two pieces make this work in Eleventy.&lt;/p&gt;
&lt;p&gt;First, a deterministic ring order. Hosts are normalized (lowercased, trailing slashes stripped) and sorted alphabetically, then shared through filters so every consumer agrees on who is next and previous:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHost&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;host &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&#92;/+$&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;orderedHosts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; collection
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHost&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;host&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ringNeighbor&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; host&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hosts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; collection
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHost&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;host&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; hosts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;normalizeHost&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;host&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; hosts&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; offset &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; hosts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; hosts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That modulo arithmetic is the whole wrap-around trick: the last site&#39;s &amp;quot;next&amp;quot; is the first site, and the first site&#39;s &amp;quot;previous&amp;quot; wraps back around to the end. A web ring should be a circle, after all.&lt;/p&gt;
&lt;p&gt;Second, a paginated template generates all the pages:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;---
permalink: &quot;/next/{{ member.data.host | hostSlug }}/&quot;
eleventyExcludeFromCollections: true
pagination:
  data: collections.members
  size: 1
  alias: member
---
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;http-equiv&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;refresh&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0; url=https://{{ collections.members | ringNeighbor(member.data.host, 1) }}/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eleventy fans that out into 63 pages, one per member, in about a third of a second. There are 63 current members at time of writing.&lt;/p&gt;
&lt;h2 id=&quot;nobody-gets-left-behind&quot; tabindex=&quot;-1&quot;&gt;Nobody gets left behind &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/improving-the-webring-links/#nobody-gets-left-behind&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Changing the widget format would normally mean asking every member to update their site. Instead, both formats work side by side:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The old &lt;code&gt;/next/?host=yourwebsite.com&lt;/code&gt; pages are untouched and keep doing their thing&lt;/li&gt;
&lt;li&gt;The new per-host pages live alongside them at &lt;code&gt;/next/&amp;lt;host&amp;gt;/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Both read from the same shared ordering, so &amp;quot;next&amp;quot; means the same neighbor no matter which style of link brought you there&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;New members copying the snippet from the &lt;a href=&quot;https://static.quest/join/&quot;&gt;join page&lt;/a&gt; get the new format; existing members can update whenever they feel like it, or never. No rush, no breaking changes. That felt like the right way to treat the folks who make the ring a ring.&lt;/p&gt;
&lt;p&gt;While improving the overall process, the random link got a small tune-up too. It used to be the same story: load page, fetch JSON, pick a winner. Now the member list is baked right into the page at build time, so clicking &amp;quot;Feeling lucky?&amp;quot; needs zero network requests beyond the redirect itself.&lt;/p&gt;
&lt;h2 id=&quot;why-this-matters&quot; tabindex=&quot;-1&quot;&gt;Why this matters &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/improving-the-webring-links/#why-this-matters&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everything above stays true to what makes a static site a static site: no server-side logic, no edge functions, no databases. Just files on a static server. The &amp;quot;dynamic&amp;quot; behavior people usually reach for JavaScript to solve turned out to be a build-time problem wearing a runtime costume, and moving it into the build made the result faster, simpler, and friendlier to browsers that don&#39;t run scripts.&lt;/p&gt;
&lt;p&gt;So go ahead, click an arrow somewhere in the ring and enjoy the tour. If you run your own site and want to join the quest, we would love to have you. Check out the &lt;a href=&quot;https://static.quest/join/&quot;&gt;joining instructions&lt;/a&gt; and add yourself to the circle.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>What is a static website?</title>
		<link href="https://static.quest/posts/what-is-a-static-site/"/>
		<updated>2026-08-24T13:28:30Z</updated>
		<id>https://static.quest/posts/what-is-a-static-site/</id>
		<content type="html">&lt;h2 id=&quot;what-is-a-static-website&quot; tabindex=&quot;-1&quot;&gt;What is a Static Website? &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/what-is-a-static-site/#what-is-a-static-website&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A static website is like a digital brochure that remains unchanged unless manually updated. Every page of a static website is a fixed HTML file, meaning the content is pre-determined and doesn&#39;t dynamically change based on user interactions or real-time data.&lt;/p&gt;
&lt;h3 id=&quot;key-characteristics-of-static-websites&quot; tabindex=&quot;-1&quot;&gt;Key Characteristics of Static Websites &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/what-is-a-static-site/#key-characteristics-of-static-websites&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Pre-built Content: All content is created and stored as individual HTML files.&lt;/li&gt;
&lt;li&gt;No Server-Side Processing: Unlike dynamic websites, static sites don&#39;t require a server to process requests and generate content on the fly.&lt;/li&gt;
&lt;li&gt;Faster Load Times: Because there&#39;s no server processing, static websites generally load much faster than dynamic ones.&lt;/li&gt;
&lt;li&gt;Limited Interactivity: While they can include basic elements like forms and images, static websites lack advanced features like user logins, personalized content, or real-time updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;when-to-choose-a-static-website&quot; tabindex=&quot;-1&quot;&gt;When to Choose a Static Website &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/what-is-a-static-site/#when-to-choose-a-static-website&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Simple Content: If your website primarily consists of text, images, and basic information, a static site is a good option.&lt;/li&gt;
&lt;li&gt;Performance Focus: Static websites are ideal for projects where fast load times are crucial, such as portfolios or online stores with a limited product range.&lt;/li&gt;
&lt;li&gt;Low Maintenance: If you don&#39;t need frequent updates or advanced features, a static website can be easier to manage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;popular-tools-for-creating-static-websites&quot; tabindex=&quot;-1&quot;&gt;Popular Tools for Creating Static Websites &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/what-is-a-static-site/#popular-tools-for-creating-static-websites&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;HTML, CSS, and JavaScript: For those comfortable with web development, creating a static site from scratch using these languages provides maximum control.&lt;/li&gt;
&lt;li&gt;Static Site Generators: Tools like Jekyll, Hugo, and Gatsby streamline the process by converting plain text and templates into HTML files.&lt;/li&gt;
&lt;li&gt;Content Management Systems (CMS): While primarily designed for dynamic websites, some CMS platforms like WordPress can also be used to create static sites, offering a more user-friendly approach.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;in-conclusion&quot; tabindex=&quot;-1&quot;&gt;In Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/what-is-a-static-site/#in-conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Static websites offer a straightforward and efficient solution for many online projects. Their simplicity, speed, and low maintenance requirements make them a popular choice for individuals and businesses with basic website needs. However, if you require more complex features and dynamic content, a dynamic website might be a better fit.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Building a static site</title>
		<link href="https://static.quest/posts/static-site-generators/"/>
		<updated>2026-08-24T13:28:30Z</updated>
		<id>https://static.quest/posts/static-site-generators/</id>
		<content type="html">&lt;p&gt;Static sites are a great part of the small web. They are easy to configure, deploy, and maintain. You can use a static site generator or write the HTML yourself.&lt;/p&gt;
&lt;h2 id=&quot;static-site-generators&quot; tabindex=&quot;-1&quot;&gt;Static Site Generators &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/static-site-generators/#static-site-generators&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To help some content producers, the use of a Static Site Generator is helpful. This allows the user to design their site and functionality, then just add content where it is needed and the generator builds complete HTML from template files. Examples of Static Site Generators (in alphabetical order):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; &lt;em&gt;(JS)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docusaurus.io/&quot;&gt;Docusaurus&lt;/a&gt; &lt;em&gt;(JS+React)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/&quot;&gt;Eleventy&lt;/a&gt; &lt;em&gt;(JS)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt; &lt;em&gt;(JS/TS+React)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt; &lt;em&gt;(Go)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; &lt;em&gt;(Ruby)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.getlektor.com/&quot;&gt;Lektor&lt;/a&gt; &lt;em&gt;(Python)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/&quot;&gt;Next.js&lt;/a&gt; &lt;em&gt;(JS/TS+React)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nuxt.com/&quot;&gt;Nuxt&lt;/a&gt; &lt;em&gt;(JS/TS+Vue)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://getpelican.com/&quot;&gt;Pelican&lt;/a&gt; &lt;em&gt;(Python)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vuepress.vuejs.org/&quot;&gt;VuePress&lt;/a&gt; &lt;em&gt;(JS+Vue)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are plenty more: &lt;a href=&quot;https://jamstack.org/generators/&quot;&gt;https://jamstack.org/generators/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most of these generators rely on technologies like NodeJS, Python, Ruby, Go and others. The generators are able to build simple personal sites to large complex business pages, the choices are endless.&lt;/p&gt;
&lt;h2 id=&quot;hosting-your-static-site&quot; tabindex=&quot;-1&quot;&gt;Hosting your Static Site &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/static-site-generators/#hosting-your-static-site&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hosting a website is the next step after building it. There are many free platforms available to host a static site, and also paid hosting options. Popular static site hosting is found at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pages.github.com/&quot;&gt;Github Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codeberg.page/&quot;&gt;Codeberg Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pages.cloudflare.com/&quot;&gt;Cloudflare Pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these providers integrate with the Git actions to build and deploy the site to their hosting platform. The addition of Git provides some with a workflow that makes it easy to add their content and publish without needing to be hands on or knowledgeable in the hosting aspect of web content.&lt;/p&gt;
&lt;p&gt;This is not a comprehensive list, but a small one to help those who wan to get into web design, blogging, and sharing their content.&lt;/p&gt;
&lt;h2 id=&quot;choosing-a-name&quot; tabindex=&quot;-1&quot;&gt;Choosing a name &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/static-site-generators/#choosing-a-name&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every website on the Internet is reached via a domain name. The choice provider for &lt;a href=&quot;https://static.quest/&quot;&gt;Static.Quest&lt;/a&gt; is &lt;a href=&quot;https://porkbun.com/&quot;&gt;Porkbun&lt;/a&gt;. They have a fun name and good prices.&lt;/p&gt;
&lt;p&gt;If you don&#39;t want to spend a lot of money yearly, many of the hosting providers mentioned also allow you to have a subdomain off of theirs for convenience.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot; tabindex=&quot;-1&quot;&gt;What&#39;s next &lt;a class=&quot;direct-link&quot; href=&quot;https://static.quest/posts/static-site-generators/#whats-next&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are so many further places we could go, but let&#39;s have some other bloggers and website developers tell you in the &lt;a href=&quot;https://static.quest/posts/resources/&quot;&gt;resources&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Just start a blog</title>
		<link href="https://static.quest/posts/resources/"/>
		<updated>2026-08-24T13:28:30Z</updated>
		<id>https://static.quest/posts/resources/</id>
		<content type="html">&lt;p&gt;Finding a good community to help you along in your web journey is a powerful thing. There are places to improve design, backend work, writing, and more. Here are a few great resources to help in some of those ideas.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://moddedbear.com/go-start-a-blog/&quot;&gt;Go start a blog&lt;/a&gt; by &lt;em&gt;Jeremy&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benjaminhollon.com/musings/blogging-on-a-budget/&quot;&gt;Blogging on a budget&lt;/a&gt; by &lt;em&gt;Benjamin Hollon&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://100daystooffload.com/&quot;&gt;100 Days to Offload&lt;/a&gt; by &lt;em&gt;Kev Quirk&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://82mhz.net/posts/2024/07/one-year-of-blogging/&quot;&gt;One year of blogging&lt;/a&gt; by &lt;em&gt;Andreas&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://claytonerrington.com/blog/year-in-review/&quot;&gt;Year in review&lt;/a&gt; by &lt;em&gt;Clayton Errington&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.ctms.me/posts/2024-08-29-running-this-blog-on-a-pixel-5/&quot;&gt;This blog is running on a recycled Google Pixel 5&lt;/a&gt; by &lt;em&gt;Dom Corriveau&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.stevefenton.co.uk/tag/jekyll/1/&quot;&gt;Jekyll Archive&lt;/a&gt; by &lt;em&gt;Steve Fenton&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.stevefenton.co.uk/tag/astro/1/&quot;&gt;Astro Archive&lt;/a&gt; by &lt;em&gt;Steve Fenton&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benjaminhollon.com/musings/the-great-paywall/&quot;&gt;The great paywall&lt;/a&gt; by &lt;em&gt;Benjamin Hollon&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benjaminhollon.com/musings/announcing-my-blogroll/&quot;&gt;Announcing my blogroll&lt;/a&gt; by &lt;em&gt;Benjamin Hollon&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.adamsdesk.com/posts/different-types-of-web-hosting-explained/&quot;&gt;Different Types of Web Hosting Explained&lt;/a&gt; by &lt;em&gt;Adamsdesk&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This list should hopefully grow and expand over time. If you have something you&#39;d like to share, send a pull request to get it added.&lt;/p&gt;
</content>
	</entry>
</feed>
