How the Sausage Garden Is Made
A field guide to the lively parts of this blog
A field guide to the lively parts of this blog
What and why
Last year, I built this blog from scratch using SvelteKit. A few days ago, I rewrote it completely in vanilla HTML, CSS, and JavaScript while keeping everything else the same. Then I rebuilt parts of it to explore non-linearity in thinking. I'm a visual thinker, and I subscribe to the philosophy that any work can be a channel for artistic expression. My blog is especially that to me: a place where I explore, tinker, reflect, learn, and build my taste.
While I love beautiful, non-linear digital spaces, like the blogs of Maggie Appleton and Amelia Wattenberger, I don't quite have their skill for creating digital works of art.
So I decided to use AI as my coach. I rebuilt my digital garden, and then had it teach me how it was done.
The result was a redesigned landing page and an experiment in adding non-linearity and life to my writing manifesto, Writing the Thing.
This post dissects the techniques used to make them.
The map
The vertical ruler on the landing page is not an image and not a series of borders. It is one line drawn behind the entire list.
First, make a coordinate system. An absolutely positioned element needs an ancestor to measure itself against. Giving the parent position: relative establishes that boundary.
Then, generate the line. ::before creates a decorative box without adding meaningless HTML. Stretch it from top: 0 to bottom: 0, and put its left edge at half the parent's width.
.timeline {
position: relative; /* establish the coordinate system */
}
.timeline::before {
content: ""; /* make the pseudo-element exist */
position: absolute;
top: 0;
bottom: 0; /* stretch it vertically */
left: 50%; /* place it in the middle */
border-left: 1px solid currentColor;
}
Character comes from recognizable choices repeated with restraint: a particular voice, a contrast between fonts, an imperfect mark, or a small surprise in an otherwise orderly system.
out.of.ordinary
made with intent, not polish ✦Repeat a few signatures. This blog reuses literary serif type, quiet monospaced labels, red hand-drawn marks, dotted phrases, and tiny rotations. Encountered together, they begin to feel like one place.
Let the words participate. Labels such as “field note,” phrases such as “out.of.lines,” and a crossed-out sausage carry the author's temperament. Personality can live in microcopy as much as in CSS.
.editorial-voice { font-family: "Iowan Old Style", serif; }
.technical-label { font-family: "Fira Code", monospace; }
.human-mark { transform: rotate(-1deg); }
/* Reuse the same small vocabulary instead of inventing
an unrelated effect for every section. */
Character is not the same as decoration. Decoration can be added anywhere. Character emerges when the same choices appear often enough to become recognizable, but not so often that they become a costume.
The posts appear to wander, but every row lives on the same strict three-column grid.
.item {
display: grid;
grid-template-columns:
minmax(0, 1fr)
3rem
minmax(0, 1fr);
}
.item.left .summary { grid-column: 1; text-align: right; }
.item.right .summary { grid-column: 3; text-align: left; }
.item .marker { grid-column: 2; }
fr means a fraction of the free space. The two 1fr columns therefore remain equal. The fixed middle column reserves breathing room around the ruler.
minmax(0, 1fr) is a defensive version of 1fr. The zero allows a long title to shrink or wrap instead of forcing the grid wider than the screen.
The page is not unaligned. It alternates between two alignments.
Left-hand entries are right-aligned as they approach the axis. Right-hand entries are left-aligned as they leave it. The eye travels across the page.
The manifesto looks loosely arranged. It is not random. Several small, repeating rules overlap until the pattern becomes difficult to notice.
li:nth-child(3n + 2) {
margin-left: clamp(0rem, 6vw, 5rem);
}
li:nth-child(4n + 1) { transform: rotate(-.45deg); }
li:nth-child(4n + 3) { transform: rotate( .55deg); }
li:hover { transform: translateX(.35rem) rotate(0); }
:nth-child() selects elements by their position. 3n + 2 means the second item in every group of three: 2, 5, 8, and so on.
clamp(min, preferred, max) is deterministic, not random. The browser calculates the preferred value at the current screen size, then prevents it from falling below the minimum or exceeding the maximum. In clamp(0rem, 6vw, 5rem), the indent is 6% of the viewport width until that value reaches the 5rem ceiling.
The restraint matters. Half a degree disturbs a baseline. Five degrees turns every sentence into a sticker. The intention is not to advertise the effect, only to make the page feel less mechanical.
The manifesto separates its repeated conclusion from its changing premises. Scroll through this section and watch the large phrase stay present.
.field {
display: grid;
grid-template-columns: 4fr 6fr;
}
.refrain {
position: sticky;
top: 3rem;
align-self: start;
}
No JavaScript is watching the scroll position. The browser works from two pieces of information: the element's normal position in the document and the boundary established by its containing section.
The element participates in normal document flow. It takes up space in the grid and scrolls toward the top like everything else.
top: 3rem establishes a constraint. When scrolling would move the element above that line, the browser offsets it just enough to hold it there.
The element is not allowed to escape its containing section. When the section's bottom reaches it, the browser stops applying that offset, and both leave the viewport together.
align-self: start also matters inside this grid. Grid items stretch by default. A stretched element can occupy the full height of its row, leaving it nowhere to travel. Aligning it to the start keeps it only as tall as its contents.
This is more than a visual trick. It lets two parts of an argument exist at once: a fixed proposition and changing examples. The same primitive could hold a question beside several answers, a hypothesis beside evidence, or an AI agent's interpretation beside its sources.
A pseudo-element can borrow the dimensions of a word, which makes it useful for marks that feel drawn onto the page.
This page was built with ordinary CSS.
.handmark {
position: relative;
display: inline-block;
}
.handmark::after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: .08em;
width: 100%;
height: .16em;
background: var(--accent);
transform: rotate(-1deg);
}
inline-block makes the wrapper exactly as wide as its contents. The generated mark can then use width: 100%.
The negative z-index places the mark behind the letters. A one-degree rotation removes its machine-perfect edge.
Hover or focus each line
The interaction should complete the thought. The negative statement receives a strike. The positive statement receives a check. The movement is small, but its meaning belongs to the sentence.
A restrained palette gives color a job. Large, carefully set type lets the words become part of the composition.
quiet pages
can still speak.
Give each color a role. Near-black carries the reading. Green labels structure and instruction. Red marks decisions, interactions, and the ideas that deserve attention. Repetition teaches the reader what each color means.
Treat type as material. Size creates hierarchy, but typeface, line height, letter spacing, and line length determine whether large text feels graceful or merely loud.
:root {
--paper: #efede6;
--ink: #20251f;
--growth: #596d50;
--signal: #b03333;
}
.display-type {
font-size: clamp(3.5rem, 10vw, 8rem);
letter-spacing: -.07em;
line-height: .85;
}
The accent colors occupy relatively little area. That scarcity gives them force. The same principle applies to scale: most text remains comfortable and quiet, allowing a few phrases to become enormous without the whole page shouting.
Whitespace is not the absence of design. It gives each idea enough time and room to arrive.
When everything arrives at once, hierarchy has to fight for attention.
Distance creates anticipation, grouping, and rest.
.chapter {
width: min(86%, 56rem); /* preserve a readable line length */
margin-bottom: clamp(9rem, 17vw, 16rem);
}
.demonstration {
padding: clamp(2rem, 5vw, 4rem);
}
Space describes relationships. A small gap says two things belong together. A large gap announces a new movement. Consistent distances become a grammar the reader can feel without naming.
Space also controls pace. The reader scrolls through quiet before encountering the next large thought. That pause is part of the experience, much like a paragraph break or a rest in music.
Gracious does not simply mean large. It means proportional. Body copy gets a comfortable line length. Related details stay close. Important transitions receive enough room to feel intentional.
CSS knows how a filtered timeline should look. JavaScript only needs to decide what is visible and which side each remaining item belongs on.
::beforefunction filterBy(tag) {
const items = document.querySelectorAll("[data-garden-tags]");
items.forEach(function (item) {
const tags = item.dataset.gardenTags.split(" ");
item.hidden = tag !== "all" && !tags.includes(tag);
});
reflowVisibleItems();
}
data-garden-tags="css writing" stores information on the element without inventing a visual class. JavaScript reads it through element.dataset.gardenTags.
After filtering, the visible items are counted again. Even-numbered items receive the left class; odd-numbered items receive the right class. JavaScript changes semantic state. CSS remains responsible for pixels.
Responsive design does not require squeezing the desktop composition into a phone. It requires deciding which idea must survive.
@media (max-width: 640px) {
.item {
grid-template-columns: 1.4rem minmax(0, 1fr);
}
.summary {
grid-column: 2;
text-align: left;
}
.refrain {
position: relative; /* stop sticking */
}
}
On this blog, the centered ruler becomes a left-hand rail. The sticky two-column manifesto becomes a normal vertical flow. Rotations and long connector lines disappear.
The choreography is sacrificed before readability is. The timeline remains a timeline. The refrain remains larger than its examples. The idea survives even when the arrangement changes.
Create a clear order.
Then let a few things
gently infuse some disorder.
Get notified when new posts are published.