Live chess over Gemini (and a short history of streaming)

Note that this webpage was originally going to be an addendum to Unicode chess over Gemini, but it quickly grew into its own topic.


Accidental duplication

The TLS identity concept I expressed in Unicode chess over Gemini (as well as another project I was working on!) was incidentally a duplication of an idea posed by solderpunk, the Benevolent Dictator of Project Gemini in A vision for Gemini applications (gemini://) on 2020/06/16:

Some of you may recognise this approach [TLS certificates for identities] as being similar to the idea of using separate browser "profiles" for different kinds of web surfing. Indeed, this is ultimately the same basic idea, it just turns out to be far more scalable and far more usable in the case of Gemini because the clients and the notion of a "profile" (basically just a client cert) are both so much slimmer that you can have and use as many of them as you want.

In the same post, solderpunk references a (now dead) post by Tomasino:

Basically, Tomasino raised the possibility of a Gemini server holding the connection with a client open for a long time and only occasionally feeding the client content, with the client taking full advantage of the possibility of rendering text/gemini line-by-line, as it comes, rather than buffering up a whole file and rendering at once when the connection closes. I think this is a really exciting idea, and I love that it leverages one of text/gemini's core strengths. In the #gemini IRC channel, xq mentioned the possibility of secure remote `tail -f`ing of server logs in this way, which is surely just scratching the surface of what could be done with this.

Now, let's put the streaming idea together with the idea of a "slightly social" version of these certificate-secured "for me, by me" apps that I'm so big on. There is no reason that pubnixes couldn't run Gemini-based chatrooms for their users in this manner!

Simultaneously while writing my previous post and exploring the underground chess scene in Gemini, I was also working on a planned follow-up project: a live chatroom server which would use an edge case of the Gemini protocol to allow for server streaming– which is exactly the concept posed by Tomasino and solderpunk.

A couple days ago while building my basic static server Canaveral, I was surprised to see that my attempt at sending a page in multiple chunks was successful; this planted the idea in my head that a server could deliberately keep a connection open to send data later. I hastily implemented a proof of concept where the server never sent a CRLF; instead it would send updates (new messages by other users) to all room members which were then appended to previous messages. Theoretically, we could use this to send a new chess board each time the other player in a two-player match made a move (my original application intention), but my focus at the moment was on the potential of a chat server.

Finding existing chatrooms

Given that I had quickly stumbled into this idea of streaming chat messages, I assumed that there were likely existing implementations; however, I struggled to find any mention on the WWW (which is not made easier by the name conflict with Google's project). Thankfully, I remembered the Gemini Mailing List Archives (gemini://) which includes a thread started on 2021/10/04 titled "chat over gemini (or, let's play with streaming text)".

As an aside, I also recommend reading through some threads on the Gemini Mailing List (gemini://) to learn more about experimental directions and applications of the Gemini protocol.

In this thread, Omar Polo introduces his "very, very simple CGI script that streams text/gemini to build an interactive chatroom." However, this was not the first instance of a Gemini chat server. In fact, Michael Lazar replied with a link to his own Gemini Chat (gemini://) and a github repo which dates the project to 2020/06/20, just four days after solderpunk's A vision for Gemini applications (gemini://). This thread by Omar Polo is also where I found solderpunk's post.

As a summary of the timeline:

  • 2020/??/??: Tomasino's "gemini streaming" post
  • 2020/06/16: solderpunk discusses TLS identity and echoes Tomasino's streaming idea
  • 2020/06/21: Michael Lazar implements solderpunk's chatroom concept (Re: A vision for Gemini applications (solderpunk) (gemini://)
  • 2021/10/04: Omar Polo independently implements an interactive chatroom with streaming
  • 2024/04/24: slondr introduces Galaxy Chat (gemini://), inspired by the #gemini IRC (I found this one via TLGS (gemini://))
  • 2026/04/16: I accidentally reinvent the wheel (live chat over Gemini)

The concept of streaming keeps organically emerging in the community, which makes sense given the WWW backdrop that has monopolized the public perception of the internet. Each time that streaming makes the rounds, it's reception is rightfully mixed, striking a balance between curiosity and the fear of deluding the good of Gemini. After all, the strength of Gemini is being deliberately not the web.

Despite offering server-driven updates, streaming has several limitations. For instance, it requires the server to hold a prolonged connection with all clients; those clients need to properly handle edge cases (such as displaying incremental chunks rather than buffering until EOF), and the connection cannot timeout. The client requirements are also not standard. Out of the three clients I have used (Lagrange, AV-98, and Elpher), only Lagrange incrementally displayed streamed chunks. Although it is within the spec, the lack of client support strongly implies that the community as a whole views streaming as a novelty at best.

Trying to force a square peg into a round hole

Although the chatroom idea is far from novel at this point, I find myself resonating with solderpunk's sentence immediately before introducing the idea:

In the #gemini IRC channel, xq mentioned the possibility of secure remote `tail -f`ing of server logs in this way, which is surely just scratching the surface of what could be done with this.

Surely, we can use the streaming concept for more than just "IRC, but worse". Perhaps, as was my original intention, we can make "online chess, but worse".

In my opinion, there are two main reasons that chatrooms made a natural application of streaming:

  1. It is highly sensitive to perceived responsiveness.
  2. The streaming model that Gemini implicitly accepts is for streaming the body of a site; as such, the client expects new chunks to be appended to the existing body which is the natural layout for chat.

Internet chess fits (1) but fails horribly from a naive perspective on (2) since chess moves are changes to the board rather than simple appended strings.

The "ideal" scenario from a usability perspective would be the ability for the server to modify all lines, not just append. In effect, this can be done with terminal control sequences on some clients. At the start of each update the server sends, it can include a command to clear the screen and replace the entire contents with what follows.

I searched for a Gemini browser that could be used for this purpose, but I was unable to find one that could successfully do both:

  1. Log incremental chunks from the server (and still be usable)
  2. Render ANSI escape codes to clear the terminal

Consider gmni (or gemget with -o-) a curl-like utility that fetches a Gemini site. Using gmni, I could request a site that includes "\033[2J\033[H" in the "text/gemini" data and my terminal would be cleared. Furthermore, it kept the connection open for additional streamed data. Since gmni is not intended to be a complete Gemini browser, it does not support simple navigation which is necessary for game input. gmnlm (from the gmni project) came the closest to satisfying both of the requirements. It can log streamed data incrementally and supports the required ANSI escaped codes, but streaming locks the interface and prevents navigation. Despite not being perfect, they still demonstrate that live streaming with arbitrary content updates (just not appending) is possible.

ANSI streaming over Gemini is not new; check out ansi.hrtk.in – play ANSI art over HTTP or Gemini, but I have not yet seen someone combine streaming with terminal control sequences on Gemini.

At this point, I was a bit stumped. I couldn't find an existing client that implements the precise edge cases that my approach requires and building a new client would defeat the purpose; I want to demonstrate what existing software and standards are already capable of. Then, I remembered that I do not actually need (or want) client streaming in full generality for the chess server… then it clicked.

Back to chess

In chess, only one of the two players is capable of moving at a time; this is unlike a chatroom where any subset of members may be trying to communicate at the same time. As a result, the server can send a full page to the active user while holding a connection with the inactive user. When the active user makes a move, the roles reverse. No refresh is required because the only time a user will need new information is after they send their own move; that is, sending a new move is tied to receiving the recipient's move, just like in single-player chess with a bot. Additionally, the newly-active user can be sent all of the relevant information at one time. Using the blocking pattern implicit in streaming, real time chess is possible without streaming support. With all of this, the only client support risk is a timeout.

I went to back to spool-five's chess (gemini://) to ensure I was not accidentally re-inventing the wheel again. To this end, I created a game with one client (elpher) then joined that game with another client (Lagrange); however, without blocking, I had to refresh the original client to see that another user had joined– which is exactly the UX friction I want to eliminate.

elpher_spool_five_queue.png

Figure 1: image of example client after the other user already joined

Armed with a goal, I quickly modified my existing chess implementation into a two-player server with the aforementioned blocking mechanism. Although it is not yet support the logistics for multiplayer (simultaneous games, player matching, etc.), it does work as intended. As a result, I plan to continue polishing it and potentially host it on a new Gemini capsule (my current Gemini capsule on a pubnix only hosts static gemtex).

As a final note, I want to explicitly state my lack of expertise; I first used a Gemini browser around ~5 days ago and although I have been reading a lot on the protocol and community, I also know enough to know that I have massive blind spots. This webpage (just like my site in general) is intended to be a casual log of my learning and experiments, so please do not assume that anything here is authoritative or novel.


Last updated April 28, 2026