Jan Miksovsky’s BlogArchive AboutContact

All City Someday: a photo blog backed by Google Drive

Suppose you want a photo blog that’s not on Tumblr or Instagram. Maybe you don’t like being sold, or want to draw outside the lines, or want photos as part of your own site. What would a #smallweb alternative look like that let you post a photo and caption from your phone?

I made a proof-of-concept street art photo blog that supports this on-phone flow: 1) snap a photo and set a caption, 2) save the photo to Google Drive via Files, 3) trigger a rebuild via the browser, 4) see the new photo on your own site.

View source

Google Drive is hardly #indieweb, but look beyond “corporate = bad” and consider the nature of the relationship. They provide a commodity service: you pay them, they store your files. Those files are a medium of exchange. If (when?) Google screws around, you can easily move the files to a different storage provider. Switching costs for hosted platforms like Tumblr or Instagram are far higher.

All storage services provide a proprietary API to enable unique features and faster service… but also to force you to write to that API and make your own code a switching cost. But most of what you want from storage is just an easy way to: 1) list directories, 2) read a whole file, and (maybe) 3) save a whole file.

The tiny AsyncTree interface does exactly those things.

interface AsyncTree {
  get(key: any): Promise<any>;
  keys(): Promise<IterableIterator<any>>;
  set?(key: any, value: any): Promise<this>;

This interface lets small storage drivers wrap the proprietary APIs; switching providers is just a matter of switching drivers.

The Origami language can use such a driver to read images out of Google Drive and create a static, deployable site. Origami templates also understand that interface, so you can make a template that directly maps a folder’s photos to HTML <img> tags with dates and captions. 🎉

One significant hurdle: obtaining a Google API credential file. OMG figuring out any kind of auth on Google, Azure, or AWS is like wandering through a maze of twisty little passages, all alike. It’s also theoretically possible to use Google Cloud Pub/Sub to automatically trigger a site rebuild whenever a photo is added to Google Drive, but dang that looks complicated. Maybe some other day.

Standards like Exif (for photo captions and dates) make amazing things possible. They’re there for everyone to use — if a corp isn’t trying to cage you in their silo.

The code for this photo blog is small: HTML + CSS + about 40 lines of Origami code. That includes defining RSS and JSON feeds. 😃

If I ever needed to switch storage providers, I’d just have to update the 3 lines of code that authenticate with Google and get a reference to the Drive folder. Everything else would stay the same.

Abstracting away storage doesn’t just give you an interesting way to build a site, it also opens up general-purpose terminal access so you can:

Design notes:

  1. It was fun to play with #CSS blur, text-shadow, and -webkit-text-stroke for a graffiti heading that’s just plain text! May also be the first time I’ve ever used magenta.
  2. I was able to auto-size the header width to be roughly as wide as the photos by playing with values for font-size: clamp(…).
  3. The fonts are so different from the stock fonts that any font swap was really jarring, so I forced early loading of the small font files and used font-display: block.

I made an ebook about my hike across Japan

I’ve made a little ebook about my hike across Japan last year.

In the summer of 2023, I walked for a month from the Pacific Coast to the Sea of Japan. I crossed steep mountains including Mt. Fuji, portions of the Southern Alps, the Yatsugatake range, the Northern Alps, and the Shio no Michi Trail. In between, I walked through cities, towns, and rural areas. The hike was a substantial challenge but also a fun adventure.

Book cover showing a grassy meadow and an elevated walking path

Creating an ebook is not difficult. Will Crichton wrote a great article advocating for using the EPUB format as a more portable and responsive alternative to PDFs.

Before reading it I hadn’t appreciated that EPUB files are just ZIP files with a particular folder structure and some book data. In retrospect that makes sense, but for me that single insight demystified the entire prospect of creating an ebook. It’s just a small bundle of files, mostly HTML, and some metadata.

You can use apps to make an ebook, but I wanted to build one more directly. Since the Origami website definition language is great at processing trees of content (like a folder of text and images) into new forms, I realized it could easily generate an ebook in EPUB format.

It wasn’t hard to write an Origami program to generate files in the required folder structure, and then it was just a matter of zipping it up.

Which left the question: what material could I turn into a book?

JamesG posted a good list of ideas for things people can do on their website. Facundo Olano expanded on that to suggest adding EPUB downloads for your blog or subsets of it. Their posts made me realize my own hike posts might make an interesting sample book.

During the hike I’d kept a travel diary in markdown with photos, so it was fairly easy to add a cover image, an introduction, and some metadata. Voilà: a book!

It may seem silly, but packaging something as a “book” feels weightier. Simply seeing the cover art in my ebook library alongside purchased novels was thrilling, as was opening up the book and paging through it. It felt like that day in third grade when a teacher had us bind illustrated stories into books and the school librarian put them on a library shelf. 📚

Try making an ebook — about anything — and you’ll feel the same thrill.

Small Web Build of a little Cat Prints online store

For this month’s #SmallWebBuild, I made a little sample store for selling art prints.

The site’s structure is defined in a single file in the Origami site design language that turns the sample artwork images and data into a gallery home page and a separate page for each print.

I built this to try out Snipcart, a web service for adding a shopping cart to a static site. They seem to charge lower fees for this service than the larger site hosting platforms, and it was trivial to add the shopping cart with a few HTML attributes. I love that their approach leaves you in control of the rest of your site. That said, I haven’t signed up to use Snipcart to actually complete financial transactions; if you’re interested in Snipcart, investigate it carefully.

I also used this store site to experiment with the new web View Transitions API. I was able to create a zoom effect that works across page navigations (!) which is completely nuts. Caveats: currently in Chrome/Edge/Opera only; it was hard to figure out how to do what I wanted; Chrome sometimes shows a white flash before the zoom-out animation. Still, I’m excited to see these effects coming to simple multi-page sites.

Internet archives are amazing and under-appreciated.

I searched a #Usenet archive for a program I’d written decades ago in high school: an interpreter for the Karel programming language for use in intro CS classes. Because wonderful people have maintained those archives for many years, I was able to find my program 40 years after I wrote it. https://www.usenetarchives.com/view.php?id=net.sources&mid=PDI5OUBzcG9jay5VVUNQPg

It’s hard to describe what it’s like to see that #C code again now. (Although I’m frankly appalled that teenage me didn’t put curly braces around one-line if clauses and for loops.)

I downloaded the source and was delighted that the ancient #Unix shell script to extract the code still runs just fine in bash. (It would take much more time to actually get the program itself to work again.) I posted the source on GitHub: https://github.com/JanMiksovsky/karel.

40 years from now, which is more likely to still exist: the USENET archive version, or the GitHub version? 🤔 I’m betting the former.

When considering modern web development, I keep two images in mind.

Gleaming Tesla gigafactory with robots and no people

This factory image captures how many devs approach creating websites: constructing an enormous, gleaming, automated system that can produce complex artifacts on a massive scale.

A potter using their hands to sculpt a clay pot on a wheel

In contrast, an individual artisan working in a studio directly creates something simple but useful using their own hands and understandable tools. To me this second image captures the #smallweb/#indieweb spirit.

Factories aren’t always bad and artisans aren’t always good, but many devs can’t conceive of building anything without first making a big factory. “You’re creating that pot by hand?? Why, a gleaming pot factory could make a million pots a day!”

That’s ridiculous. A factory — even one magically built for you — can easily become a monstrosity you don’t understand but have to maintain. In many cases simple tools produce better results than a factory. And some of us like making things by hand!

The Origami language gives web creators functions for making parts of web sites in the same way a spreadsheet offers functions for crunching numbers: give a function some input, get something useful back.

Case in point: every so often I want a web page to show a screenshot of another web page. Puppeteer is great for that but cumbersome to set up, so I made screenshot functions: give them HTML or a URL, get back an image.

I used this to make a new Examples page on the Origami docs site. A build script uses the screenshot function to take pictures of each sample URL, producing a virtual folder of images that get saved as real images for deployment. This will make it easy to add new samples or update the screenshots as the sample sites evolve.

Small Web Build video of sample Cherokee Myths site

I enjoy videos of people showing off small homes they’ve built or van conversions they’ve done. The person shows off their craftwork, describes goals and trade-offs, recommends tools/components/techniques, and shares lessons learned. It makes building something feel approachable and can inspire people to try it themselves.

I’d love to see #smallweb/#indieweb creators do the same with #SmallWebBuild videos. Here’s my first.

This walks you through the Cherokee Myths site I described previously that uses Origami to create a static site with a generated table of contents, plus a full-text search feature using Pagefind by Liam Bigelow.

Using small home and van build videos as models, the following could make for good #SmallWebBuild videos:

Cherokee Myths sample Origami site with a table of contents and full-text search

I built a sample Cherokee Myths site to explore how easy it is to create a static site in Origami that includes a generated table of contents and full-text search. I’m happy with how the site turned out.

Cherokee Myths site home page with a table of contents listing myths grouped by topic

As described in the site source, the site’s overall structure is defined in a single concise Origami file that orchestrates the creation of the table of contents on the home page, the generation of search indexes, and the processing of the tree of markdown content into HTML.

Diagram of navigational structure of the Cherokee Myths site

The tree of stories is flattened by a template to create the table of contents, and that same tree is also fed to a great tool called Pagefind to generate search indexes to allow full-text search on the static site.

Search page showing that "hummingbird" produces two hits

Using public domain content for this sample was way more interesting than lorem ipsum text, and the Cherokee myths have a distinctly different mood than Greek myths or Aesop’s fables. The tale of the The Race Between the Crane and the Hummingbird did not end the way I’d expected.

Cherokee Myth of the Race Between the Crane and the Hummingbird

This sample also gave me a chance to place with two recent CSS additions: text-wrap: balance so that long headings end up with lines roughly equal in length (instead of a long line followed by an orphaned word), and initial-letter to add a drop cap at the start of the story text.

Update: I made a video tour of this site.

Origami language as a complement to HTML/CSS/JS

Writing about the incompleteness of HTML/CSS/JS has helped me reframe my Origami language as a way to complement those native web languages.

People with some experience with HTML and CSS (but maybe not JS) have a world of ideas to share but may struggle with those missing platform pieces. Origami is a small language to round out the standard ones so people can make even cooler sites, especially small and independent sites.

The Origami language is small and focused on common web tasks. I take inspiration from the core W3C principle of the Rule of Least Power: choose the least powerful programming language for a given purpose.

Web diagrams look deceptively complete

I see so many web platform diagrams that represent HTML/CSS/JS in a tidy, complete arrangement that suggests those are everything you need to know — when in reality those only let you define what happens in individual pages. A more realistic diagram would be incomplete! You’re going to need to choose and master additional technologies to create a coherent, functional site.

Two bubble diagrams: Left shows HTML, CSS, and JavaScript; Right adds bubbles with question marks for site structure, server, and HTML reuse

Even the simplest possible static site requires site structure (organizing the files into a folder hierarchy) and a server that can respond to web requests with those files. A non-trivial site generally also requires some way to reuse HTML across pages. Where is all that represented in the first diagram?

JavaScript developers will happily explain that their preferred language can be used for all those purposes via Node, so for them the first diagram is actually complete. That’s great for them! (I use Node too.)

But many people don’t want to learn JavaScript or find it too difficult, and for basic sites it’s massive overkill. Moreover, the diagram on the left suggests you can’t build a page without JavaScript, but I think JavaScript on the front end should be used sparingly.

Older posts