Archive for the ‘Mastodon’ Category

Introducing Pinafore for Mastodon

Today I’m happy to announce a project I’ve been quietly working on for some time: Pinafore. Pinafore is an alternative web client for Mastodon, which looks like this:

Screenshot of Pinafore home page

Here are some of its features:

  • Speed. Pinafore is built on Svelte, meaning it’s faster and lighter-weight[1] than most web apps.
  • Simplicity. Single-column layout, easy-to-read text, and large images.
  • Multi-account support. Log in to multiple instances and set a custom theme for each one.
  • Works offline. Recently-viewed timelines are fully browsable offline.
  • PWA. Pinafore is a Progressive Web App, so you can add it to your phone’s home screen and it will work like a native app.
  • Private. All communication is private between your browser and your instance. No ads or third-party trackers.

Pinafore is still beta quality, but I’m releasing it now to get early feedback. Of course it’s also open-source, so feel free to browse the source code.

In the rest of this post, I want to share a bit about the motivation behind Pinafore, as well as some technical details about how it works.

If you don’t care about technical details, you can skip to or read the user guide.

The need for speed

I love the Mastodon web app, and I’ve even contributed code to it. It’s a PWA, it’s responsive, and it works well across multiple devices. But eventually, I felt like I could make something interesting by rewriting the frontend from scratch. I had a few main goals.

First off, I wanted the UI to be fast even on low-end laptops or phones. For Pinafore, my litmus test was whether it could work well on a Nexus 5 (released in 2013).

Having set the bar that high, I made some hard choices to squeeze out better performance:

  • For the framework, I chose Sapper and Svelte because they offer state-of-the-art performance, essentially compiling to vanilla JavaScript.
  • To be resilient on slow connections, or Lie-Fi, or when offline altogether, Pinafore stores data locally in IndexedDB.
  • To use less memory, Pinafore keeps only a fraction of its UI state in memory (most is stored in IndexedDB), and it uses a fully virtual list to reduce the number of DOM nodes.

Other design decisions that impacted performance:

I also chose to only support modern browsers – the latest versions of Chrome, Edge, Firefox, and Safari. Because of this, Pinafore is able to directly ship modern JavaScript instead of using something like Babel to compile down to a more bloated ES5 format. It also loads a minimum of polyfills, and only for those browsers that need them.

Privacy is key

Thanks to the magic of CORS, Pinafore is an almost purely client-side web app[2]. When you use the Pinafore website, your browser communicates directly with your instance’s public API, just like a native app would. The only job of the server is to serve up HTML, CSS, and JavaScript.

This not only makes the implementation simpler: it also guarantees privacy. You don’t have to trust Pinafore to keep your data safe, because it never handles it in the first place! All user data is stored in your browser, and logging out of your instance simply deletes it.

And even if you don’t trust the Pinafore server, it’s an open-source project, so you can always run it locally. Like the Mastodon project itself, I gave it an AGPL license, so you can host it yourself as long as you make the modified source code available.

Q & A

What’s with the name?

Pinafore is named after my favorite Gilbert and Sullivan play. If you’re unfamiliar, this bit from The Simpsons is a great intro.

Does it work without JavaScript?

Pinafore’s landing page works without JavaScript for SEO reasons, but the app itself requires JavaScript. Although Server-Side Rendering (SSR) is possible, it would require storing user data on Pinafore’s servers, and so I chose to avoid it.

Why are you trying to compete with Mastodon?

Pinafore doesn’t compete with Mastodon; it complements it. Mastodon has a very open API, which is what allows for the flourishing of mobile apps, command-line tools, and even web clients like or Pinafore itself.

One of my goals with Pinafore is to take a bit of the pressure off the Mastodon project to try to be all things to all people. There are lots of demands on Mastodon to make small UI tweaks to suit various users’ preferences, which is a major source of contention, and also partly the motivation for forks like glitch-soc.

But ideally, the way a user engages with their Mastodon instance should be up to that user. As a user, if I want a different background color or for images to be rendered differently, then why should I wait for the Mastodon maintainers or my admin to make that change? I use whatever mobile app I like, so why should the web UI be any different?

As Eugen has said, the web UI is just one application out of many. And I don’t even intend for Pinafore to replace the web UI. There are various features in that UI that I have no plans to implement, such as administration tools, moderation tools, and complex multi-column scenarios. Plus, the web UI is the landing page for each instance, and an opportunity for those instances to be creative and express themselves.

Why didn’t you implement <x feature>?

As with any project, I prioritized some features at the expense of others. Some of these decisions were based on design goals, whereas others were just to get a working beta out the door. I have a list of goals and non-goals in the project README, as well as a roadmap for basic feature parity with the Mastodon web UI.

Why didn’t you use the ActivityPub client-to-server API?

ActivityPub defines both a server-to-server and a client-to-server API, but Mastodon only supports the former. Also, Mastodon’s client-to-server API is supported by other projects like Pleroma, so for now, it’s the most practical choice.

What’s your business model?

None. I wrote Pinafore for fun, out of love for the Mastodon project.

How can I chip in?

I’m a privileged white dude living in a developed country who works for a large tech company. I don’t need any donations. Please donate to Eugen instead so he can continue making Mastodon better!


If you’ve read this far, give Pinafore a try and tell me what you think.


1. Measuring the size of the JavaScript payload after gzip when loading the home feed on a desktop browser, I recorded 333KB for Pinafore, 1.01MB for, and 2.25MB for

2. For the purpose of readable URLs, some minor routing logic is done on the server-side. For instance, account IDs, status IDs, instance names, and hashtags may be sent to the server as part of the URL. But on modern browsers, this will only occur if you explicitly navigate to a page with that URL and the Service Worker hasn’t already been activated, or you hard-refresh. In the vast majority of cases, the Service Worker should handle these URLs, and thus even this light metadata is not sent to the server.

Decentralized identity and decentralized social networks

I’d like to tell you a story about Bob. Bob is a fairly ordinary, upstanding citizen. Bob also has a lot of hobbies.

Bob is a good father, so one of his hobbies is to coach his son’s little-league team. Bob is careful to enforce a certain set of rules during the games and at the after-game pizza parties. If one of the kids uses a curse word or bullies another kid, Bob is expected to intervene and apply the appropriate discipline.

Bob is also a Christian. When he’s in church on Sundays, there’s another set of rules, both implicit and explicit, that Bob is expected to abide by. For instance, it’s okay for Bob to confide in other churchgoers about his momentary lapses of faith, or about his struggles to understand certain Bible passages. But if Bob started quoting Richard Dawkins or loudly preaching atheism, he’d probably create a very awkward scene, and may even get kicked out of church.

Bob also happens to be a vegetarian, and he attends a monthly vegetarian meetup. Within this group, there’s an entirely different set of rules and norms at play. Bob is careful not to talk too much about his favorite recipes involving cheese, eggs, or honey, because he knows that there’s a sizable minority of vegans in the group who may be offended. It would also be completely unacceptable to talk about a juicy steak dinner, even though this topic of conversation may be perfectly acceptable within the church or the little-league team.

Bob also has a set of old college buddies that he occasionally meets up with at the local bar. Here, once again, an entirely different set of norms apply. Raunchy jokes and curse words are not only allowed – they’re encouraged. Open debate about religion is tolerated. Bob may even be able to let his vegetarian guard down and talk about a delicious steak dinner he ate in a moment of weakness.

One Bob out of many

Bob intuitively understands these different norms and contexts, and he effortlessly glides from one to the other. It’s as if there’s a switch in his brain that activates as soon as he walks through the church doors or into the bar.

Furthermore, nobody accuses Bob of being dishonest or duplicitous for acting this way. In fact, everything described above is such a fundamental, everyday part of the human experience that it’s downright boring.

Now Bob goes online. Suddenly, every social network is telling him that he should have exactly one identity, speak in one voice, and abide by one set of rules. Mark Zuckerberg says, “Having two identities for yourself is an example of a lack of integrity.” OKCupid says, “We want you […] to go by who you are, and not be hidden beneath another layer of mystique.” Eric Schmidt says, “If you have something that you don’t want anyone to know, maybe you shouldn’t be doing it in the first place.”

Bob is apparently expected to use his real name, and use one account, and present a single public face for every possible context and social situation.

Intuitively, Bob knows this is bullshit. We all know it’s bullshit. But in the online world, we’ve just learned to put up with it.

Identity on social networks

Now let’s step away from Bob for a moment and talk about how the rest of us deal with this problem.

One of the common coping mechanisms is to fracture ourselves into different silos. We use Slack to talk to our coworkers, Discord to chat with our gamer buddies, LinkedIn for professional talk, Twitter for talking about the news, Facebook for talking with our family, and so on. Folks who follow this strategy may use a completely different voice in each platform and may not even reveal their real names.

With decentralized social networks, though, the situation gets more interesting. On platforms like Mastodon, Pleroma, GNU Social, postActiv, and others, you sign up for a particular “instance” representing a self-contained community. This community may have its own rules, its own culture, and even its own emojis and theme color.

However, each instance isn’t walled off from the outside world. Instead, it has tendrils that can reach into any other community it may be connected to. It’s less like the isolated silos of Facebook, Twitter, and Slack, and more like a cluster of small towns with some well-traveled roads between them.

Some folks look at Mastodon as a mere replacement for Twitter. Maybe for them it’s Twitter for lefties, or Twitter for anime artists, or Twitter for a nationalist agenda. It’s really none of these things, though, and I think importantly it has the potential to address one of the biggest problems with online identity: context collapse.

Context collapse

“Context collapse” was first coined by danah boyd, and a good description of it can be found in a blog post by Michael Wesch.

The basic idea is this: when human beings converse in person, we use a wide variety of unwritten rules to govern the acceptable boundaries of the conversation. We pick up on subtle nonverbal cues such as someone’s posture, their hand gestures, and their degree of eye contact to choose the right “register” for the conversation. We might even switch between different dialects of the same language, depending on who we’re talking to (linguists call this “code-switching”).

All of this happens automatically and intuitively, and it’s a valuable tool for avoiding ambiguities and misunderstandings. There are entire subfields of linguistics that study how humans communicate this way, such as pragmatics and sociolinguistics.

Online, we have none of this context. Staring into the webcam or into the textbox on a social media site, we are simultaneously addressing everyone and no one, for now and for all time. Factor in character limits, upload limits, and just the limits of human attention, and this is a ripe environment for misunderstandings. Sarcasm, facetiousness, irony, playful ribbing between friends – all of it can be lost on your audience if they don’t have the proper context to guide them.

Here are some of the symptoms of context collapse that you may have experienced:

  • jokes are misunderstood and taken at face value
  • in-jokes between friends are perceived as harassment by outsiders
  • you accidentally offend someone when no offense was intended
  • something you say is taken out of context and used for dogpiling
  • you feel like you have to censor yourself online
  • you agonize over every character and punctuation mark to avoid misinterpretation

All of these situations can be frustrating or even harmful to your mental health. Consider Justine Sacco’s poorly-received joke that cost her her job and brought her a lot of mental anguish.

Fracturing ourselves into siloed social networks, in its own ham-handed way, offers a solution to this problem. Instead of just hoping that our readers will pick up on the context, we rely on the context granted by the social network itself. Discord is for gamers, LinkedIn is for professionals, Slack is for coworkers, etc.

But on decentralized social networks, we may have a more elegant solution to this problem, and one that doesn’t require locking up our identities into various proprietary silos.

Solving context collapse on decentralized social media

The notion that you should use a single identity online is, I believe, a holdover from the centralized social media sites. Their goal is to get you to reveal as much information about yourself as possible (to sell it to advertisers), so of course they would discourage you from having multiple accounts or from concealing your real name. But that doesn’t mean decentralized social networks need to be the same.

Instead of treating your identity “on Mastodon” or “on the fediverse” as a single entity, what if you had multiple identities on multiple instances, and you treated them as distinct? What might that look like?

I figured this out myself over the past year or so, as I largely split my online identity on Mastodon into two accounts: and

The tone of the two accounts is completely different. makes silly jokes and mostly writes in all lowercase. talks about software, programming, and his day job, and tends to use proper punctuation. (It’s more like the voice of this blog.)

The reason for this split is partly historical. tends to speak only in jokes because it was my first Mastodon account, and when I signed up I didn’t reveal my full name or tie it back to my real-world identity. Instead, I just tried to have fun, making as many silly jokes as I could and seeing what landed and what didn’t. I’d say I did fairly well, since at one point I had the most-favorited Mastodon post of all time and got quoted twice in this article on Mastodon.

Screenshot of Mastodon post saying "mom: hey son I joined this new Mastodon thing me: oh shit mom, I coulda helped you find a server, which one did you choose? mom: well I liked the privacy policy on but then had the shortest ping latency so"

When I set up my own instance, though, things started to get complicated. Now I had an admin account,, and I needed to talk about serious admin stuff: when was the server going down for maintenance, what was our privacy policy, what was our moderation policy, etc. So for that account, I switched to my professional voice so that folks could understand that I wasn’t joking or being sarcastic.

But I still had for the silly stuff. And the more I used it, the more I found that I liked the split. People who followed me on didn’t necessarily care about Mastodon admin topics (memory usage, systemd, Ruby, etc.) – maybe they only followed me for the fun stuff. Likewise, people who followed me on maybe just wanted to keep up-to-date on Mastodon admin and development (especially as I started contributing to the Mastodon codebase itself), and didn’t care for the jokes.

Keeping my identities separate thus served a few purposes:

  • I could have fun with people who didn’t know or care about tech topics (e.g. my wife, who loves my jokes but finds tech boring).
  • Nobody had to wonder when I was being sarcastic and when I was being serious.
  • People who followed me for tech stuff didn’t have to put up with my jokes if they didn’t like my sense of humor.
  • People who liked both my jokes and my tech talk could still follow me on both accounts.

This process wasn’t without its hurdles, though. At one point I was using fairly similar avatars for each account:

Screenshot of two Mastodon avatars, one with a subtle coffee icon and one without

My original Mastodon account avatars. Could you tell the difference between the two?

Eventually, though, I got tired of people not picking up on the sarcasm in my joke account. So I switched to an avatar that could only be interpreted as something silly:

Picture of a Mastodon avatar that looks like Ogmo from the Jumper game but handrawn, a silly face with bug eyes

My new, unambiguously “zany” Mastodon avatar.

Taking this avatar seriously would be like arguing with the “We Rate Dogs” account on Twitter. The new avatar makes the intent of the account much clearer.

Am I being duplicitous? No, I link between the two accounts on my profile pages, so everyone can figure out that both accounts are me.

Is it hard to juggle two different accounts? No, I use separate browser tabs, and since has its own theme color, it’s easy for me to remember which site I’m on.

Screenshot of Mastodon toot saying "tfw I have to switch from my joke account to my serious account to boost a toot, to make it clear I am not boosting ironically"

Is it hard for others to know which Nolan to talk to? Well, sort of. When my wife wants to post something like “@nolan said to me today…” she tends to use my account because she has more fun interacting with that account than with my serious one. But other than that, I haven’t really run into any problems with this system.

Previously, I was also running a French-language account at, but I found this a bit hard to manage. I didn’t have a network of French-speaking friends I was regularly talking to, and most of the francophones on Mastodon can speak English anyway. Also, managing three social media accounts was just a bit too much of a time investment for me.

Instance policies and identity

Right now I have a simple two-account system, and my choice of instance for each account is fairly arbitrary. (Although is somewhat tech- and programming-themed, so talking about computery stuff there feels very natural.) However, you could imagine tailoring an account to its home instance, based on the instance’s theme or moderation policies.

Going back to the Bob example, let’s imagine that Bob sets up four instances:

  1. An instance for his son’s little-league team, which is closed off from most of the fediverse via whitelisting and has very strict moderation policies to ensure it stays kid-friendly. All of the parents have moderator accounts.
  2. An instance for his church group. The moderation policies reflect Christian values, and although you can talk openly about your faith, it’s advised to use Content Warnings for controversial topics.
  3. An instance for his vegetarian meetup. You’re encouraged to take pictures of your food, but pictures of meat dishes are strictly off-limits. Vegetarian (non-vegan) food photos are okay, but should be hidden behind a “sensitive” tag.
  4. A free-for-all instance for his drinking buddies. Anything goes, say whatever racy or off-color joke pops into your head, but be aware of the consequences – such as the fact that other instances might not want to federate with you. You might also want to use a pseudonym here instead of your real name.

Bob could create a separate account on all four instances, and he might speak in a very different voice on each of them. If he’s an admin or a moderator, he may even enforce very different policies, and he might choose different instances to block or silence. In fact, one of his instances may even block the other! Via whitelisting, the kid-friendly one certainly blocks the drinking-buddies instance.

Bob’s not doing anything wrong here. He’s not a hypocrite. He’s not being deceitful. He’s just taking exactly the same logic that we use in the real world, and applying it to the online world.


It’s unreasonable to expect people to speak in the same voice in every social setting offline, so it’s equally unreasonable to ask them to do it online.

In the world of centralized social networks, users have responded to “real name policies” and “please use one account” by fracturing themselves into different proprietary silos. On decentralized social networks, we can continue fracturing ourselves based on instances, but these disparate identities are allowed to comingle a bit, thanks to the magic of federation.

I don’t expect everyone to use the same techniques I use, such as having a joke account and a serious account. For some people, that’s just too much of an investment in social media, and it’s too hard to juggle more than one account. But I think it’s a partial solution to the problem of context collapse, and although it’s a bit of extra effort, it can pay dividends in the form of fewer misunderstandings, fewer ambiguities, and less confusion for your readers.