matrix.org/content/blog/2020/12/2020-12-18-introducing-ceru...

9.7 KiB
Raw Permalink Blame History

+++ title = "Introducing Cerulean" path = "/blog/2020/12/18/introducing-cerulean"

[taxonomies] author = ["Matthew Hodgson"] category = ["General"]

[extra] image = "https://matrix.org/blog/img/2020-12-18-cerulean.png" +++

Hi all,

We have a bit of an unexpected early Christmas present for you today…

Alongside all the normal business-as-usual Matrix stuff, weve found some time to do a mad science experiment over the last few weeks - to test the question: “Is it possible to build a serious Twitter-style decentralised microblogging app using Matrix?”

It turns out the answer is a firm “yes” - and as a result wed like to present a very early sneak preview of Cerulean: a highly experimental new microblogging app for Matrix, complete with first-class support for arbitrarily nested threading, with both Twitter-style (“vertical”) and HN/Reddit-style (“horizontal”) layout… and mobile web support!

Cerulean screenie

Cerulean is unusual in many ways:

  • Its (currently) a very minimal javascript app - only 2,500 lines of code.
  • It has zero dependencies (other than React).
    • This is to show just how simple a fairly sophisticated Matrix client can be...
    • ...and so the code can be easily understood by folks unfamiliar with Matrix...
    • ...and so we can iterate fast while figuring out threading...
    • ...and because none of the SDKs support threading yet :D
  • It relies on MSC2836: Threading - our highly experimental Matrix Spec Change to extend relationships (as used by reaction & edit aggregations) to support free-form arbitrary depth threading.
  • As such, it only works on Dendrite, as thats where weve been experimenting with implementing MSC2836. (Were now running an official public Dendrite server instance at dendrite.matrix.org though, which makes it easy to test - and our test Cerulean instance https://cerulean.matrix.org points at it by default).

This is **very much a proof of concept. **Were releasing it today as a sneak preview so that intrepid Matrix experimenters can play with it, and to open up the project for contributions! (PRs welcome - it should be dead easy to hack on!). Also, we give no guarantees about data durability: both Cerulean and dendrite.matrix.org are highly experimental; do not trust them yet with important data; we reserve the right to delete it all while we iterate on the design.

What can it do?

So for the first cut, weve implemented the minimal features to make this something you can just about use and play with for real :)

  • Home view (showing recent posts from folks you follow)
  • Timeline view (showing the recent posts or replies from a given user)
  • Thread view (showing a post and its replies as a thread)
  • Live updating (Its Matrix, after all! Weve disabled it for guests though.)
  • Posting plain text and images
  • Fully decentralised thanks to Matrix (assuming youre on Dendrite)
  • Twitter-style “Vertical” threading (replies form a column; you indent when someone forks the conversation)
  • HN/Reddit/Email-style “Horizontal” threading (each reply is indented; forks have the same indentation)
  • Basic Registration & Login
  • Guest support (slightly faked with non-guest users, as Dendrites guest support isnt finished yet)
  • Super-experimental proof-of-concept support for decentralised reputation filtering(!)

Obviously, theres a huge amount of stuff needed for parity with a proper Twitter-style system:

  • Configurable follows. Currently the act of viewing someones timeline automatically follows them. This is because Dendrite doesnt peek over federation yet (but its close), so you have to join a room to view its contents - and the act of viewing someones timeline room is how you follow them in Cerulean.
  • Likes (i.e. plain old Matrix reactions, although we might need to finally sort out federating them as aggregations rather than individually, if people use them like they use them on Twitter!)
  • Retweets (dead easy)
  • Pagination / infinite scrolling (just need to hook it up)
  • Protect your posts (dead easy; you just switch your timeline room to invite-only!)
  • Show (some) replies to messages in the Home view
  • Show parent and sibling context as well as child context in the Thread view
  • Mentions (we need to decide how to notify folks when theyre mentioned - perhaps Matrixs push notifications should be extended to let you subscribe to keywords for public rooms youre not actually in?)
  • Notifications (although this is just because Dendrite doesnt do notifs yet)
  • Search (again, just needs to be implemented in Dendrite - although how do you search beyond the data in your current homeserver? Folks are used to global search)
  • Hashtags (its just search, basically)
  • Symlinks (see below)
  • Figure out how to handle lost unthreaded messages (see below)
  • Offline support? (if we were using a proper Matrix SDK, wed hopefully get this for free, but currently Cerulean doesnt store any state locally at all).

How does it work?

Every message you send using Cerulean goes into two Matrix rooms, dubbed the "timeline" room and the "thread" room. The "timeline" room (with an alias of #@matthew:dendrite.matrix.org or whatever your matrix id is) is a room with all of your posts and no one else's. The "thread" room is a normal Matrix room which represents the message thread itself. Creating a new "Post" will create a new "thread" room. Replying to a post will join the existing "thread" room and send a message into that room. MSC2836 is used to handle threading of messages in the "thread” room - the replies refer to their parent via an m.relationship field in the event.

These semantics play nicely with existing Matrix clients, who will see one room per thread and a flattened chronological view of the thread itself (unless the client natively supports MSC2836, but none do yet apart from Cerulean). However, as Cerulean only navigates threaded messages with an m.reference relationship (eg it only ever uses the new /event_relationships API rather than /messages to pull in history), normal messages sent by Matrix into a thread or timeline room will not yet show up in Cerulean.

In this initial version, Cerulean literally posts the message twice into both rooms - but were also experimenting with the idea of adding “symlinks” to Matrix, letting the canonical version of the event be in the timeline room, and then the instance of the event in the thread room be a symlink to the one in the timeline. This means that the threading metadata could be structured in the thread room, and let the user do things like turn their timeline private (or vice versa) without impacting the threading metadata. We could also add an API to both post to timeline and symlink into a thread in one fell swoop, rather than manually sending two events. Itd look something like this:

Cerulean diagram

We also experimented with cross-room threading (letting Bobs timeline messages directly respond to Alices timeline messages and vice versa), but it posed some nasty problems - for instance, to find out what cross-room replies a message has, youd need to store forward references somehow which the replier would need permission to create. Also, if you didnt have access to view the remote room, the thread would break. So weve punted cross-room threading to a later MSC for now.

Needless to say, once were happy with how threading works at the protocol level, well be looking at getting it into the UX of Element and mainstream Matrix chat clients too!

Whats with the decentralised reputation button?

Cerulean is very much a test jig for new ideas (e.g. threading, timeline rooms, peeking), and were taking the opportunity to also use it as an experiment for our first forays into publishing and subscribing to reputation greylists; giving users the option to filter out content by default they might not want to see… but doing so on their own terms by subscribing to whatever reputation feed they prefer, while clearly visualising the filtering being applied. In other words, this is the first concrete experimental implementation of the work proposed in the second half of Combating Abuse in Matrix without Backdoors. This is super early days, and we havent even published a proto-MSC for the event format being used, but if youre particularly interested in this domain its easy enough to figure out - just head over to #nsfw:dendrite.matrix.org (warning: not actually NSFW, yet) and look in /devtools to see whats going on.

So, there you have it - further evidence that Matrix is not just for Chat, and a hopefully intriguing taste of the shape of things to come! Please check out the demo at https://cerulean.matrix.org or try playing with your own from https://github.com/matrix-org/cerulean, and then head over to #cerulean:matrix.org and let us know what you think! :)