GeistHaus
log in · sign up

https://barnabas.me/rss.xml

rss
30 posts
Polling state
Status active
Last polled May 18, 2026 23:45 UTC
Next poll May 20, 2026 00:58 UTC
Poll interval 86400s
ETag W/"8a9fa2cefeba5e32d5a41dc0630279da"

Posts

Cheaty Flashcards
I made a flashcard app in Vue
Show full content

import cheaty_flashcards_play from "~/assets/blog/cheaty-flashcards-play.png";

My niece just finished the fourth grade and we were commiserating about learning multiplication tables. We thought, what if there was a game for learning math that let you cheat just a little bit so you don't get too discouraged? Soon after, Cheaty Flashcards was born.

<img class="md:float-right md:ml-4" src={cheaty_flashcards_play} width="321" height="315" alt="Cheaty Flashcards gameplay"

</img>

Some of the tech choices I made are as follows. I reached for my favorite Vue + Vite combo and used the TypeScript starter. I styled it with Tailwind CSS and daisyUI, a great combination of sensible boilerplate and flexibility. Other dependencies include Unhead for dynamic page titles, Fontsource for the web font Fredoka, and unplugin-icons to embed Feather SVGs as components. The new-to-me library this time was howler.js for playing sound effects.

I pushed the app source code to a private GitHub repository. I'm using Cloudflare Pages as the host and tracking usage with Beam Analytics. The whole thing took only a few hours between idea and v1 on the web.

Some may see the above and bemoan the state of frontend development. "What ever happened to FTPing some static files to a shared web server?" they cry, yelling at the cloud. I'm tempted to agree, especially for a little free toy app. But, tooling like this brings the ability to build complexity and make changes rapidly. And personal projects like these are to me what practicing scales are to a musician.

https://barnabas.me/blog/2023/06/cheaty-flashcards/
Starlight
Astro's Starlight project is the next VitePress
Show full content

This month I had the opportunity to take Starlight for test drive as a demo for my team's internal documentation. Although Starlight currently comes with a warning that it's in early development, we were impressed by its polish and features. I think it has real potential to challenge established documentation SSGs like VitePress or Docusaurus.

If you already have Markdown files, it is absurdly easy to publish them with Starlight. Those are basic table stakes for any SSG, though. If you need to do something unusual in your docs site, such as host an API or enforce authentication, good news! Starlight is built on Astro, so you have the full power of Astro and its integrations at your disposal. For our demo, I enabled diagrams with the astro-diagram plugin. Like any Astro site, you can create components in Astro's syntax or any supported framework including React, Preact, Svelte, Vue, SolidJS, AlpineJS and Lit.

Documentation is not worth much if the content is not discoverable. You can configure the sidebar manually or just point a sidebar section at a directory, which is nice. But Starlight's pièce de résistance IMO is the excellent static site search courtesy of Pagefind, and I'm already a fan. Other solutions in this space don't have a built-in search, have a very minimal search UI, or rely on an external service like Algolia.

The drawback of Starlight, aside from its wet-behind-the-ears newness, is the inflexibility. There's no way to make a custom page that uses the Starlight's layout, as of today. You can only have one sidebar, so this might make certain kinds of documentation difficult or impossible. VitePress supports multiple sidebars if that's a deal breaker. It is certainly difficult to balance simplicity with customizability.

For our use case, we ultimately decided against using Starlight in favor of GitHub's wiki feature. It might look comparatively boring and have a terrible search UX, but GitHub's wiki edit and publish workflow is good enough for internal documentation. Besides, access is already restricted to the team members, something we'd have to replicate somehow with Starlight.

https://barnabas.me/blog/2023/06/starlight/
Trying Out Nuxt
My experience trying to port an app from Astro to Nuxt
Show full content

I have enjoyed using Astro to run both this site and DBaaS Review. I've written before about Astro now and again. Recently I decided to migrate DBaaS Review from Astro on Render to Nuxt on Cloudflare.

My original motivation was receiving a bill from Render for DBaaS Review's API. Now $7/month is pretty reasonable, but it got me to thinking. If I could switch from Render to Cloudflare Pages, I might be able to stay within the free tier for a while. Plus, having two different projects, one for the API and another for the UI, was getting tiresome. How good would it be to have just one static frontend with a dynamic API, all hosted on the edge for free?

As long as I was going to tear everything apart, I thought "why not try Nuxt?" After all, Nuxt/Nitro has a Cloudflare Pages preset. So I merged the Express API with the Astro site to form a single Nuxt app. It went fairly well at first, and Nuxt has a slick DX. I especially appreciated the file-based-routing for the API endpoints. It was tedious converting the JSX-like .astro files to .vue components, but I prefer the Vue syntax anyway, especially for loops:

Astro
---
const visible = true;
const items = ["Dog", "Cat", "Platypus"];
---
{visible && <p>Show me!</p>}
<ul>
  {items.map((item) => (
    <li>{item}</li>
  ))}
</ul>
Vue
<script setup>
import { ref } from "vue";
const visible = ref(true);
const items = ref(["Dog", "Cat", "Platypus"]);
</script>
<template>
  <p v-if="visible">Show me!</p>
  <ul>
    <li v-for="item in items">{{ item }}</li>
  </ul>
</template>

I ended up getting stuck on some sharp edges with the Nuxt/Cloudflare migration. One was that I just couldn't find a nice way for Nuxt to find and open a SQLite file. I finally realized that Cloudflare Pages' workers would never allow me to access the filesystem and load a SQLite file anyway.

Discouraged, I tried implementing a combined app with Astro in Docker. It went very smoothly. I was able to reuse much of the work I did for the Nuxt API endpoints, and reading the SQLite file worked without a fuss. Astro's Docker SSR recipe worked well. Now that I had a containerized app, I was able to deploy my app to Fly.io. Render and Fly both have a free tier which they spin down services for inactivity, but unlike Render, Fly.io's spin up seems speedy enough that it doesn't feel like a penalty. Fly Machines are Firecracker VMs that boot in about 300ms. Goodbye, Render.

Could a containerized Nuxt have worked on Fly.io? Likely yes. Could SSR Astro have worked on Cloudflare? Maybe? I admit to my bias and laziness; Nuxt had to be much better than Astro to be worth the migration hassle, but it just wasn't. They're both about equal in terms of Pros and Cons, except I'd give the edge to Astro's docs right now. I'm glad I tried Nuxt and I think for a brand new app I'd try it again. But then again, I might experiment with SvelteKit or SolidStart instead. Anything but Next.js/React. :nauseated_face: PHP even.

As for the main thing I don't like about Astro, the JSX style templates? Using SSR Vue components within Astro is feasible to a point. But, there are certain things that can only happen inside an .astro file, so I just have to learn to live with weird loops and conditionals.

https://barnabas.me/blog/2023/05/trying-nuxt/
Beam Analytics
I'm switching my sites from Plausible to Beam Analytics
Show full content

This site is hosted on Cloudflare Pages, and so I have some visibility to the traffic. Still, it's useful to have more details than the Cloudflare analytics provide. Years ago the default option would have been Google Analytics, but there are more privacy-friendly alternatives available now.

Until today I was using Plausible Analytics on this site and my side project. It costs $9.75/month which felt pretty reasonable at the time. I am nowhere near the 10k page views that would force me to upgrade my plan, though. When calculated as price per page view even now, it's... a lot. That's especially in light of everything else here (except for the domain name) being free.

The other day however, I saw an HN post about Beam Analytics (affiliate link). The free tier is 100k page views per month, and that seems like a nice value. I will try it out and probably cancel my Plausible plan.

https://barnabas.me/blog/2023/04/beam-analytics/
Employment Update
New job at Fidelity Solutions
Show full content

I just started working for a consulting firm called Fidelity Solutions. In the past I've worked with some folks who are there now, so that made it easy to join. I'm really looking forward to working with them again on projects larger than what I could take on solo.

I'm grateful that the new job allows me a schedule to continue doing volunteer work. Time is a more precious commodity than we often realize.

I was trying out UpWork but it never really worked out, maybe because I put very little effort into it. Still, I've taken down the links to UpWork from the home page and support page, likely permanently. My time is now devoted to the new job and volunteer work.

https://barnabas.me/blog/2023/04/employment/
Pagefind
Static site search with Pagefind
Show full content

I have developed and written about my own static site search library for Astro. It was fun and instructive. I learned more about search, Astro's inner workings, and practiced publishing an NPM package.

I wanted to provide something as easy to configure and use as the original VuePress static search. It should be possible to whip up a markdown-driven static site with a decent search without begging Algolia for help. The problems I faced with this solution were:

  • It was very Astro-specific, deeply tied to Astro's rendering pipeline.
  • I never provided a plug-and-play UI component, the documentation was just "here's an idea, good luck."
  • It was going to be a ton of work to keep updated.

I found an integration with a new library called Pagefind through the Astro integrations library. In many ways it is technically superior. It indexes the static output HTML after the build, so works with any SSG, not just Astro. There's a default UI that works Just Fine after a little CSS tweaking. You can easily customize how content is indexed. Unlike my library, it actually displays highlighted content excerpts. There's a lot to like, and I appreciate CloudCannon's work on this.

My main complaint is that it does not split documents by heading. I have some long-ish documents and the search only helps you know the query is somewhere in the page. However, this feature appears to be on the roadmap, so I'll keep an eye out.

Will I continue to maintain my own astro-minisearch library? Time will tell. For now, I recommend you try out Pagefind and see if it works for you.

https://barnabas.me/blog/2023/04/pagefind/
Astro v2.0
Some thoughts after an upgrade from v1.6 to v2.0
Show full content

In my continuing Astro saga, here's the latest chapter. This post marks the completion of this site's Astro v2 upgrade. Rather than explain how to upgrade because that already exists, this is more of my thoughts and impressions on how the upgrade went.

Since that last post where I said "I should work on a plugin for Astro + MiniSearch", I went ahead and did that. At the end of January 2023, Astro v2 launched. One of the headline features was Content collections, something similar to Nuxt Content. If you consider .md files to be data and .astro files to be presentation, then keeping them separated makes tons of sense.

Although I didn't have to use the new content collections, part of this site's raison d'être is to understand and extend Astro, so I went for it. If it wasn't for my search plugin, upgrading probably would have been fairly smooth. I think the Astro team did a phenomenal job once again of documenting how to do it and keeping breaking changes to a minimum. In particular, the "Migrating from File-Based Routing" section was clutch.

For the most part, things Just Worked. Things I like about Astro v2:

  • Markdown and MDX plugin configuration is improved.
  • Using content collections is just cleaner than file-based routing -- for example, you don't have to specify layout in the frontmatter of every blog post anymore.
  • Upgrades to Vite 4, which increases my confidence that Astro will continue to stay modern.

Not so great:

  • I had a lot of trouble porting my search indexer endpoint. I got the cryptic error ReferenceError: Cannot access '_page9' before initialization at first, and the "generating static routes" step would just die silently. I finally figured out that all content fetching code had to exist inside of the get() function, not just at the top of the file like before.
  • Relative links and images in markdown files that were migrated to content collections were initially broken.
  • If you use schemas but you don't define a particular property, when you try to output the undefined property in a component, Astro will hide it instead. That is the Zod library's default behavior and can be overridden.
  • A weird error from an old workaround in astro-icon took a while to find and remove.
  • Content collections schemas get very odd if you color outside the lines.

More detail about that last one. It's cool to define collection schemas, but they are sort of generated at build time I guess? The documentation is still a little sparse, or maybe my use case is extreme. For this site, I have two content collections, blog and articles that I want to index for search. Both collections have a mandatory title attribute and an optional description. The documentation describes CollectionEntry class but it's not clear how to use it.

In the end I sort of figured it out, but it's not ideal. I used CollectionEntry<any> in my search indexer and defined a base search item schema with Zod. I used Zod's extend method to "inherit" from a common set of searchable document fields. Instead, I wish there was a ContentEntry<"search"> type without requiring an empty "search" collection. Since I'm ignoring the type anyway there's little purpose to the fancy schema. That may be a microcosm of TypeScript's overall failures though.

https://barnabas.me/blog/2023/03/astro-2/
Fair Tickets Follow-up
Follow-up to my proposal about ticket auctions and the discussion
Show full content

My post about selling tickets fairly generated a lively discussion at Hacker News with over 330 comments. As of this moment my analytics shows 10.9k unique visitors from that page, the majority (6.8k) from HN. The HN crowd is generally quite thoughtful and experienced, so there is lots of good stuff there.

The top comment was from user buro9, a technologist with inside music industry experience. I'm grateful for the time he spent adding his valuable perspective to the discussion. I especially appreciated his link to red ocean vs. blue ocean strategy, it's worth a read. At the risk of paraphrasing poorly, I understand the primary objection to be that a descending price auction is in nobody's interest except for wealthy fans. Promoters and venues prefer sales to be finalized as early as possible. Meanwhile, artists want all the seats filled with their most ardent (but possibly poorer) fans. He says a Dutch auction is antithetical to Taylor Swift's core brand and would be "flat-out" rejected. Would it, though?

As far as the needs of promoters and venues, I'm tempted to shrug who cares about them. Prioritizing The System over The Fans has led to the present rotten mess. But, there's no escaping that promoters and venues are stakeholders. Would a Dutch auction be materially worse for promoters and venues somehow? I wasn't convinced by any reasons put forth in that thread. The sale might take a different shape than what they're used to, but that doesn't make it worse. Regardless of a theoretical revenue difference, detailed pricing information from the auction would be invaluable. Unless scalpers are somehow sharing their sales numbers, that data is currently unavailable. Information that unlocks future revenue is likely more valuable than one-time revenue.

But let us fantasize briefly about an alternate reality where a superstar artist could dislodge Ticketmaster's chokehold (all historical evidence to the contrary). I believe a Dutch auction would be a big upgrade in ticket purchase fan experience, and that's something any artist should be interested in. In a world of rapid inflation, the descending price aspect would be a fan-friendly move artists could brag about. Superfans could plausibly score dirt-cheap tickets in the nosebleed seats at the last minute. How is that possible today?

Dutch auction or not, the final ticket price should be all-inclusive. Not charging extra fees and taxes is crucial for a pleasant checkout experience, and the dynamic pricing of an auction can more easily enable that. The current system's bait-and-switch dark UX patterns, obnoxious fees, and unpredictability leave them feeling anxious and ripped off. Are artists 100% sure that their fans' animus is only directed at Ticketmaster/LiveNation? Anyway, a descending price auction is but one tool for the difficult and interesting problem of improving ticket sales.

There were objections to my using the word "fair" to describe the Dutch auction system. The idea that the people with all the money always seem to hoard the nice things seems deeply unfair. Agreed. I don't know how an equitable or charitable ticket sale would work, but that wasn't my focus. I meant "fair" in the sense that as a consumer, I expect to be able to make a purchase with minimal shenanigans. I don't want to feel like I'm trying to win a game that's rigged against me. I will continue to try to improve my word choice.

There was a Twitter thread by Ian Hogarth (co-founder of Songkick, sad story): "A few thoughts on Ticketmaster and @taylorswift13". That spurred another interesting HN discussion related to this topic.

https://barnabas.me/blog/2022/11/fair-tickets-followup/
How To Sell Tickets Fairly
A proposal of how to sell a limited number of tickets to a live concert in a fair way
Show full content

import dutch_auction from "~/assets/blog/dutch-auction.jpg";

Update: there's a lively discussion at Hacker News and a follow-up post.

Earlier this week, millions of people tried to purchase Taylor Swift concert tickets at the same time. It was a complete fiasco. Ticketmaster crumbled under the high demand and everyone was angry.

Of course Ticketmaster bears primary responsibility, not just for this incident, but also for monopolizing a broken marketplace they are unmotivated and unlikely to fix.[^1] One big problem is in the structure of the sale itself: all tickets go on sale simultaneously.[^2] This creates the conditions for digital line cutting and stampedes, which then fuel a predatory secondary market. You could hardly create a more chaotic and user-hostile system if you tried.

On the other hand, selling tickets with a slow descending-price (or "Dutch") auction would be much better for everyone except ticket scalpers. This was apparently how tulips used to be sold. Maybe this hasn't caught on yet because auctioning concert tickets was protected by a patent that just expired in 2020.

<a href="https://commons.wikimedia.org/wiki/File:Aalsmeerse_bloemenveiling_een_van_de_veilingzalen,_Bestanddeelnr_933-9410.jpg"> <img src={dutch_auction} alt="Rob Croes for Anefo, CC0, via Wikimedia Commons" /> </a>

Here is how I imagine the live concert ticket auction would work:

  1. Tickets go on sale for a high price per seat (say $2,000) six months before the concert date. The bare minimum ticket price is set at $20 (Kurt Cobain would have liked that). Every concert date and venue would be a separate auction.
  2. If tickets go from $2,000 to $20 linearly over 180 days, then every day the asking price for a ticket would go down by $11. Each hour ticket prices would drop by $0.46 ($1,980 / 4,320 hours); each minute, nearly a penny. The ticket sales page would show the current ticket price and the number of tickets left. What you pay for a ticket depends on when you buy it.
  3. 14 days before the concert the ticket price would be $174 (all fees and taxes included[^3]). Someone buying 4 tickets on that day would first pre-authorize their credit card for $696. If approved, they could choose some available seats and make the purchase.

Two buyers might try for the same exact seats at the same moment, but that is much less likely in a slow single-bid auction like this. True, the deepest pockets would win the best seats, that is no different than now. Concerts in affluent areas might sell out earlier, but people living in areas with less might pay less too. The fair price for each seat in each venue would be determined naturally by the local market, an economist's dream scenario. Scalping tickets or running bot farms to snatch tickets early would be risky and unprofitable.

Rather than a mad crush of millions on day one, the system would handle a reasonable volume of transactions per hour. Lower peaks would translate into lower costs. The platform could embrace automation and offer an open API rather than fighting an anti-cheating arms race. Fans would be happier for not going through "several bear attacks" for their tickets, and artists would keep more of what belongs to them. I'm not naïve though; the most serious barriers to this becoming a reality are probably not technical.

Shameless plug: I understand how to make and launch exactly this kind of system, at least technically. If you want it built, please contact me.

[^1]: Ticketmaster would rather that you blame "evil bots", hilariously. In their help article "Why am I getting a 'blocked', forbidden', or '403 error' message" it says:

> Sorry, you've been temporarily blocked from buying tickets because you may have refreshed your browser too frequently. When that happens our system thinks it’s a bot, an evil automated program trying to scoop up tickets. And we automatically block bots.

[^2]: For popular events, Ticketmaster uses something they call the Smart Queue. Even in this recent case, there was an attempt to spread out the tsunami wave with a "Verified Fan Presale". These measures were, shall we say, inadequate.

[^3]: People hate fees and it makes them feel ripped off. It also makes pre-authorization work as expected. Since the price is absolutely flexible, then you could calculate the pre-tax "price" after the fact. This is all paid for by money that would have otherwise gone to scalpers and the "evil bots".

https://barnabas.me/blog/2022/11/selling-tickets-fairly/
Node.js + Docker Development
A quick tip on how to develop a Node.js project with Docker
Show full content

A page about how to Dockerize a Node.js application exists on the Node.js site. There is a corresponding page about using containers for development on Docker's site. Those guides are fine in theory. In practice, it can be a little tricky to use a dev server like Vite or Astro on your local machine with Docker Desktop. For example, you may find that HMR appears to work when you save a file, and yet the browser window doesn't refresh automatically.

Partly to record how to do it for myself, I created a demo repo on GitHub for Astro + Docker. Here's what's most important. The Dockerfile looks like this:

FROM node:18-alpine
WORKDIR /app
COPY package*.json .
RUN npm ci --audit=false --fund=false
CMD ["npm", "start"]

...and the docker-compose.yml file looks like this:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - "./:/app"
      - "/app/.tscache"
      - "/app/dist"
      - "/app/node_modules"

Notice that the usual COPY statement to copy the source files appears to be missing. That is intentional. When docker compose runs, our files are mounted as a volume from the local file system and shared with Docker. Thus the files we change in the editor are the same as what the Node.js process running inside the container is monitoring, not a copy. Voilà.

Even so, I prefer to shut Docker down and run my code directly Node.js on my local machine whenever possible.

https://barnabas.me/blog/2022/09/node-docker-dev/