[A screenshot of the site from 2007 with a minimal design and a single column of content with a figure element embedded and floated to the right of the text.] A screenshot of the site from 2007 with a minimal design and a single column of content with a figure element embedded and floated to the right of the text.
Figure 1

A screenshot of the original design that started exploring how media could be better integrated into content. The execution created a non-trivial amount of friction due to the markup and styling required to make it work.


Bear with me because there’s a decades-long story of exploration and experimentation that has led to where this site is today, and it’s difficult to separate the process from the result.

Initial Exploration

I originally started building my own blog with MovableType and eventually TextPattern. When Garrett Murray created Simplelog on Rails, I switched over right away. But (other) Garrett eventually moved on from Simplelog, and I migrated to Tumblr and eventually Jekyll with the hope that a static site generator was a safe long-term bet. I’ve tinkered with other tools over the years as well—mostly via enterprise CMS projects. Through all of that exposure, I never stumbled across anything that really meshed with my workflows.

Years ago, I started exploring the idea of how to support richer embedded media in my writing with a blog post titled ‘Designing for Content’. (Figure 1) That was before responsive design, and I still had a lot to learn about design, typography, and layout. But it was a start.

While I was better able to support richer blog posts, the friction of writing more markup for embedding images and the references to those images impeded writing. The pages were designed entirely around an idealized scenario where every blog post had lots of images, quotations, and other elements. In practice, though, plenty of posts only ever needed to be text, and the pages felt empty as a result.

I wrote less because the format made anything less than robust blog posts feel like they were missing something. It felt like I was on to something, but it was clear that it would take a lot more work to really nail the execution.

[A screenshot of the site from 2022 illustrating the minor design evolution while maintaining a single column of content with a figure element embedded in the text but not floating in the margin.] A screenshot of the site from 2022 illustrating the minor design evolution while maintaining a single column of content with a figure element embedded in the text but not floating in the margin.
Figure 2

A screenshot of the evolved design that started exploring how media could be better integrated into content. The execution created a non-trivial amount of friction due to the markup and styling required to make it work.


Workflow Improvements

Over the years, the design evolved and matured. (Figure 2) After migrating the site to Jekyll and static HTML pages, I began to really enjoy writing posts directly in my text editor. That enabled snippets and other shortcuts which drastically reduced the friction of more complex blog posts. I also modified the visual design to feel less incomplete when a blog post was just text without any kind of other media. These changes brought the vision a little bit closer, but it still wasn’t a sustainable long-term approach.

I eventually took the automation a step further and explored using a Ruby script to help with coding for content. It automated some of the more tedious tasks of writing with multiple images, but the process of editing was still incredibly tedious and error-prone.

Even though the script got me started on new posts faster and snippets made it faster to write the necessary markup, if I ever wanted or needed to change the markup for all figures, the effort to go back and manually update every instance would have been too much. It wasn’t ever going to be a sustainable approach. Also, if I needed to rearrange elements on the page, I’d have to manually reorder all of the figure numbers. It was error-prone and inefficient. So while it felt like I was getting closer, there was still a chasm to cross.

A Long Pause

With my amputation recovery, two small children, and an inter-state move, life just didn’t leave much space to figure it all out. Add in the fact that sites needed to be responsive, and I simply didn’t have the ability to get it right. So it went on the back burner as “good enough” until 2022.

For decades, I believed that one should never build their own content management system. There’s certainly no shortage of cases where someone built a custom tool and launched it with a single blog post that talks about the tool itself only to never publish another post again. (I’ve got several of these posts in my own archives.)

Mostly, I still believe that, but after enough years and experience with different systems and looking for tools that could support the vision, nothing ever quite worked. Add in a few other considerations for my personal goals over the next twenty years, and it just made sense to bite the bullet and design something to meet my peculiar requirements.

That brings us to the current incarnation. With more front-end experience and deeper Ruby and Rails knowledge, I started tinkering with an ERb-based approach to Markdown and using helpers to generate the markup for elements and tie everything together.

Pulling it All Together

The route was circuitous, but after enough exploration of site layouts, content management systems, sel-publishing some books, a lot more Rails and SaaS experience, and some advancements in modern web browsers, the vision started to come together. Since the design and concepts were only evolutions of previous iterations, I was able to focus on the logistics writing and publishing with Markdown and ERb helpers.11A reasonable person might wonder why I didn’t use MDX, and I certainly considered it. However, with a strong preference and familiarity for Ruby, I knew I’d be better able to complete and maintain everything if it was all in one language.

All of the existing content had to be updated to leverage the new approaches. Thankfully, with years of accumulated blog posts, those Markdown files also served as a great test bed to ensure that all of the machinations would work across different contexts and scenarios. With a lot of Regular Expression work, I was eventually able to massage all of the content into hybrid Markdown/ERb files that could be processed by the new system.

Since the content and design were only evolutions, I was free to spend the majority of time dialing in the writing and publishing process and organizing the application in a way that would make it easier to maintain and evolve over time. Like any project, the initial version represented maybe a quarter of the original vision. But it was a start.

Centering the Reader

While there was certainly a lot of work around the processes and workflows, serving the reader was the primary goal. Writing and sharing more frequently meant it would be easier to put ideas out there, but they still needed to be accessible and comfortable to read. Thankfully, none of the visitor-centric work was particularly innovative or complex, but I certainly under-estimated just how much there was to do.

Accessibility should go without saying, but since the web still has a long ways to go towards being consistently accessible, it’s worth explicitly calling out that accessibility should be the baseline. Naturally, the site had to be responsive. It also had to support both light and dark modes with an option to override their system defaults in case they preferred a specific option here. Similarly, I wanted visitors to be able to choose their own syntax highlighting theme for the code samples. There’s currently only three options, but they’re extendable so I can add more options in the future. Of course, the syntax options also play along with the light and dark color schemes.

[A screenshot of the site viewed at the five different breakpoints that affect content and layout.] A screenshot of the site viewed at the five different breakpoints that affect content and layout.
Figure 3

Ensuring that the more complex markup would flow smoothly and work at different breakpoints was challenging.


While I’ve taken extreme care to ensure maximum readability through design, I’ve also ensured that “Reader Views” are fully supported in browsers. Moreover, with semantic markup, the RSS feeds provide a robust and feed-friendly way to read the content as well.

And finally, the site offers settings and preferences that can be adjusted by visitors so they can dial in their options. While the settings were limited at launch, the system is built to be extended and offer additional options over time. With the settings and preferences, visitors can choose a “Site Fidelity” option that can reduce the amount of optional assets that are loaded and thus improve speed and accessibility on older devices or slower connections. The option defaults to the full experience currently, but if or when I add JavaScript features or web fonts, those will be off by default in order to balance experience and performance as well as to show how progressive enhancement can provide a range of options for visitors in different contexts.

Owning My Content

In the spirit of the IndieWeb movement and POSSE, publishing on a hosted tool or platform wasn’t a great fit. Using Rails, I knew I’d have robust options for either syndicating to a central tool that could push content to other platforms or syndicating directly to other platforms. In either case, I wouldn’t be limited where I could ultimately publish content.

Writing in a Text Editor

Like most developers, the more code you write, the more your text editor becomes a familiar and well-worn tool. So manipulating prose and code using a textarea in a web form was never going to cut it. Nothing beats writing and publishing directly in a text editor without needing to copy and paste content into web forms. Moreover, I wanted to be able to move between writing content and modifying source code without needing to context-switch.

I also wanted to be able to seamlessly integrate visuals, code samples, and data tables into prose without having to write HTML. (Figure 4) Having used Jekyll and Liquid for years, vanilla Markdown got me pretty far, but it was sustainable with the amount of richer elements I preferred to include in posts.

More than Markdown

Markdown is great for writing prose, but it’s not great for other types of content that involve richer, semantic markup. Having seen the power of MDX, it was clearly possible to have more advanced options, but as a Rails developer, MDX didn’t feel like the right fit. So I built a solution that let me embed ERb directly in Markdown files. (Figure 5)

content/markdown-erb-sample.md <%= ref 'guide-sample-screenshot' %><%= visual 'guide-sample-screenshot', pull: 'margin', alt: "A screenshot of the top of the Guide.", caption: "Visuals can easily be embedded semantically." %>
Figure 5

A variety of ERb helpers streamline embedding visuals, code samples, and data tables into Markdown. For example, the earlier images in this post along with their figure references have all been generated by using ERb helpers.


The guide provides more details on the available helpers and the resulting markup generated by them. The code samples helper is the most complex of the available helpers because it supports syntax highlighting, optional line numbers, and line highlighting. The best part of all of these helpers is that the resulting markup is semantic and accessible, but it can easily be updated in the future to make the most of new browser features or if there’s a reason to switch away from Cloudinary.

ActiveRecord for Views

Having used Rails for well over a decade, the power of ActiveRecord for organizing and displaying content carried some serious appeal. However, if the content lived in Markdown files and YAML frontmatter, that wasn’t an option. So the system had to reliably convert the Markdown files to database records in a way that enabled the use of ActiveRecord for views.

So while all of the content is stored in Markdown files, the system converts those files into database records with every release, and then the Rails portion takes over and serves content like any other application.

Creating a Playground

While it wasn’t a core goal, having a Ruby/Rails playground where I could explore ideas is a really handy bonus. I’m able to try out new gems, new libraries, and new approaches to solving problems without the risk associated with exploring a new idea on a product that can’t afford downtime or lost productivity.

I’m also able to eventually build small custom tools that could be served off of a subdomain of the site while being able to leverage all of the existing bits of the application to not have to spin up an entirely new Rails application to try out a new idea for a simple tool.


The site has its own colophon page that provides more robust details the technologies used to build the site.