This week we had a local-first workshop at offline in Berlin, co-organized with the p2panda project. As I’ve written about before, some of us have been exploring local-first approaches as a way to sync data between devices, while also working great offline.
We had a hackfest on the topic in September, where we mapped out the problem space and discussed different potential architectures and approaches. We also realized that while there are mature solutions for the actual data syncing part with CRDT libraries like Automerge, the network and discovery part is more difficult than we thought.
The issues we need to address at the network level are the classic problems any distributed system has, including:
Discovering other peers
Connecting to the other peers behind a NAT
Encryption and authentication
Replication (which clients need what data?)
We had sketched out a theoretical architecture for first experiments at the last hackfest, using WebRTC data channel to send data, and hardcoding a public STUN server for rendezvous.
A few weeks after that I met Andreas from p2panda at an event in Berlin. He mentioned that in p2panda they have robust networking already, including mDNS discovery on the local network, remote peer discovery using rendezvous servers, p2p connections via UDP holepunching or relays, data replication, etc. Since we’re very interested in getting a low-fi prototype working sooner rather than later it seemed like a promising direction to explore.
The p2panda project aims to provide a batteries-included SDK for easy local-first app development, including all the hard networking stuff mentioned above. It’s been around since about 2020, and is currently primarily developed by Andreas Dzialocha and Sam Andreae.
The architecture consist of nodes and clients. Nodes include networking, materialization, and an SQL database. Clients sign and create data, and interact with the node using a GraphQL API.
As of the latest release there’s TLS transport encryption between nodes, but end-to-end data-encryption using MLS is still being worked on, as well as a capabilities system and privacy-respecting deletion. Currently there’s a single key/value CRDT being used for all data, with no high-level way for apps to customize this.
The idea for the workshop was to bring together people from the GNOME and local-first communities, discuss the problem space, and do some initial prototyping.
For the latter Andreas prepared a little bookmark manager demo project (git repository) that people can open in Workbench and hack on easily. This demo runs a node in the background and accesses the database via GraphQL from a simple GTK frontend, written in Rust. The demo app automatically finds other peers on the local network and syncs the data between them.
We had about 10 workshop participants with diverse backgrounds, including an SSB developer, a Mutter developer, and some people completely new to both local-first and GTK development. We didn’t get a ton of hacking done due to time constraints (we had enough program for an all-day workshop realistcally :D), but a few people did start projects they plan to pursue after the workshop, including C/GObject bindings for p2panda-rs and an app/demo to sync a list of map locations. We also had some really good discussions on local-first architecture, and the GNOME perspective on this.
Thoughts on Local-First Architectures
The way p2panda splits responsibilities between components is optimized for simple client development, and being able to use it in the browser using the GraphQL API. All of the heavy lifting is done in the node, including networking, data storage, and CRDTs. It currently only supports one CRDT, which is optimized for database-style apps with lots of discrete fields.
One of the main takeaways from our previous hackfest was that data storage and CRDTs should ideally be in the client. Different apps need different CRDTs, because these encode the semantics of the data. For example, a text editor would need a custom text CRDT rather than the current p2panda one.
Longer-term we’ll probably want an architecture where clients have more control over their data to allow for more complex apps and diverse use cases. p2panda can provide these building blocks (generic reducer logic, storage providers, networking stack, etc.) but these APIs still need to be exposed for more flexibility. How exactly this could be done and if/how parts of the stack could be shared needs more exploration :)
Theoretical future architectures aside, p2panda is a great option for local-first prototypes that work today. We’re very excited to start playing with some real apps using it, and actually shipping them in a way that people can try.
There’s a clear path towards first prototype GNOME apps using p2panda for sync. However, there are two constraints to keep in mind when considering ideas for this:
Data is not encrypted end-to-end for now (so personal data is tricky)
The default p2panda CRDT is optimized for key / value maps (more complex ones would need to be added manually)
This means that unfortunately you can’t just plug this into a GtkSourceView and have a Hedgedoc replacement. That said, there’s still lots of cool stuff you can do within these constraints, especially if you get creative in the client around how you use/access data. If you’re familiar with Rust, the Workbench demo Andreas made is a great starting point for app experiments.
Some examples of use cases that could be well-suited, because the data is structured, but not very sensitive:
Thanks to Andreas Dzialocha for co-organizing the event and providing the venue, Sebastian Wick for co-writing this blog post, Sonny Piers for his help with Workbench, and everyone who joined the event. See you next time!
In celebration of the 45 release we had a hackfest and release party in Berlin last week. It was initially supposed to be a small event, but it turns out the German community is growing more rapidly than we thought! In the end we were around 25 people, about half of them locals from Berlin :)
Since many of the GNOME OS developers were in town for All Systems Go, this was one of the main topics. In addition to Valentin, Javier, and Jordan (remote), we also had Lennart from systemd and Adrian from carbonOS and discussed many of the key issues for image-based operating systems.
I was only present for part of these discussions so I’ll leave it to others to report the results in detail. It’s very exciting how things are maturing in this area though, as everyone is standardizing on systemd’s tools for image-based OSes.
On Saturday the primary topic was local-first. This is the idea that software should always work offline, and optionally use the network when available for device sync and collaboration. This allows for people to own their data, but still have access to modern features like multiplayer editing.
People in the GNOME community have long been interested in local-first and we’ve had various discussions and experiments in this direction over the past few years. However, so far we have not really investigated how we’d implement it at a larger scale, and what concrete steps in that direction would look like.
For context, any sync system (local-first or not) needs the following things:
Network: Device discovery, channel to send the actual data, way to handle offline nodes, encryption, device authentication, account management
Sync: Merging data from different peers, handling conflicts
UI: User interface for viewing and manipulating the data, showing sync status, managing devices, permissions, etc.
Local-first usually refers to systems that do the “sync” part on the client, though that doesn’t mean the other areas are easy :)
Adam Wiggins stopped by on Saturday morning to tell us about his work on Muse, a local-first whiteboard app for Apple platforms. While it’s a totally different tech stack and background, it was super interesting because Muse is one of very few consumer apps using local-first sync in production today.
Some of my takeaways from the session with Adam:
Local-first means all the logic lives in the client. In the Muse architecture, the server is extremely simple, basically just a dumb pipe routing data between clients. While data is not encrypted end-to-end in their case, it’s possible to use this same architecture with E2E.
Merge conflicts are not as big a deal as one might think, and not the hardest problem to solve in this space.
Local-first is a huge opportunity for desktop projects like GNOME. We were not really able to be competitive with proprietary software in the past decade on features like sync and multiplayer because we can’t realistically run huge cloud services for every single app/use case. Local-first could change this, since the logic is shifting back to the client. Servers become generic dumb pipes, which all kinds of apps can use without needing their own custom sync server.
To learn more about Muse, I recommend watching Adam’s Local-First Meetup talk from earlier this year, which touches on many of the topics we discussed in our hackfest session as well.
Other Relevant Art
The two projects we discussed as relevant art from our community are Christian Hergert’s Bonsai, and Carlos Garnacho’s work on RDF sync in tracker (codename “Emergence”).
Bonsai is not quite local-first architecturally, since it assumes an always-on home server. This server hosts your data and runs services, which apps on your other devices can use to access data, sync, etc. This is quite different from the dumb pipe server model discussed above, and of course comes with the usual caveats with any kind of public-facing service on local networks (NAT, weird network configurations, etc.).
Codename “Emergence” is a way to sync graph databases (such as tracker’s SPARQL database). It only touches on the “sync” layer, and is only intended for app data, e.g. bookmarks, contacts, and the like. There was a lot of discussion at the hackfest about whether the conflict resolution algorithm is/could be a CRDT, but regardless, using this system for syncing some types of content wouldn’t affect the overall architecture. We could use it for syncing e.g. bookmarks, and share the rest of the stack (e.g. network layer) with other apps not using tracker.
By the end of the hackfest, we had a rough consensus that long-term we probably want something like this:
Muse-style architecture with dumb pipe sync servers that only route encrypted traffic between clients
Some kind of system daemon that apps can use to send packets to sync servers, so they don’t all have to run in the background
The ability to fall back to other kinds of transport with full compatibility, e.g. local network or USB keys
A client library that makes it easy to integrate sync into apps, using well-established CRDTs
However, there was also a general feeling that we want to go slowly and explore the space before coming up with over-engineered solutions. To this end, we think the best next step is to try CRDTs in small, self-contained apps. We brainstormed a number of potentially interesting use cases, including:
Alarms: Make extra sure you hear your alarms by having it synced on all devices
Scratchpad: Super simple notepad that’s always in sync across devices
Emoji history: The same recently used emoji on all devices
Podcasts: Sync subscription list, episode playback state, per-episode progress, currently played episode, etc.
Birthday reminders: Simple list of birthdays with reminder notifications that syncs across all devices
For a first minimum viable prototype we discussed ways to cut as many corners as possible, and came up with the following plan:
Use an off-the shelf plain text CRDT to build a syncing scratchpad as a first experiment
To avoid having to deal with servers, do peer-to-peer transfer only and send data via WebRTC data channel
For peer discovery, just hardcode a public WebRTC STUN server in the client
Simple Rust GTK app mostly consisting of a text area, using gstreamer for WebRTC and automerge for CRDTs
Sync only between two devices
We’ll see how this develops, but it’s great to have mapped out the territory, and put together a concrete plan for next steps in this direction. I’m also conscious that we’re a huge community and only a handful of people were present at the hackfest. It’s very likely that these plans will evolve as more people get involved and we get more experience working with the technology.
If you’d like to experiment with this in your own app and have any questions, don’t hesitate to reach out :)
Jonas has had an open merge request for a transparent panel for a number of years, and while we’ve tried to get it over the line a few times we never quite managed. Recently Adrian Vovk was interested in giving it another try, so at the hackfest him and Jonas sat down and did some archaeology on Jonas’ old commits, rebased it, got it to work agian, and opened a new merge request.
While there are still a few open questions and edge cases, it’s early in the cycle so there’s a real chance that we might finally get this in for 46 :)
A few other things I was involved with during the hackfest:
Julian looked into one of my pet bugs: The default generated avatars when you create a new account not looking like AdwAvatar, but using an older, uglier implementation. This is surprisingly tricky because GDM/GNOME Shell can’t show GTK widgets, and the exported PNG avatars from libadwaita can only be exported at the size they’re being displayed at (which is smaller than in GDM/GNOME Shell).
We worked a bit on Annotations in Evince with Pablo, and also interviewed Keywan about how they use annotations in the editorial process for their magazine.
DieBahn was officially renamed to Railway, and we discussed next steps for the app and train APIs in general. Railway works for so many providers by accident, because so many of them use the same backend (HAFAS), but it’d be great to have actual open APIs for querying trains from all providers. Perhaps we need a lobbying group to get some EU legislation for this? :)
We discussed a “demo mode”, i.e. an easy way to set up a device with a bunch of nice-looking apps, pre-loaded with nice-looking content. One potential approach we discussed was a script that installs a set of apps, and sets them up with data by pre-filling their .var/app/ directories. The exact process for creating and updating this data would need looking into, but I’m very interested in getting something set up for this, because not having it really our software hard to demo.
Marvin showed me how he uses CLion for C/Vala development, and we discussed what features Builder would need to gain for him to switch from his custom Vala setup in CLion to Builder.
Thanks to Sonny for co-organizing, Cultivation Space for hosting us, and the GNOME Foundation for financial sponsorship! See you next time :)
Window management is one of those areas I’m fascinated with because even after 50 years, nobody’s fully cracked it yet. Ever since the dawn of time we’ve relied on the window metaphor as the primary way of multitasking on the desktop. In this metaphor, each app can spawn one or more rectangular windows, which are stacked by most recently used, and moved or resized manually.
The traditional windowing system works well as long as you only have a handful of small windows, but issues emerge as soon the number and size of the windows grows. As new windows are opened, existing ones are obscured, sometimes completely hiding them from view. Or, when you open a maximized window, suddenly every other window is hidden.
Over the decades, different OSes have added different tools and workflows to deal with these issues, including workspaces, taskbars, and switchers. However, the basic primitives have not changed since the 70s and, as a result, the issues have never gone away.
While most of us are used to this system and its quirks, that doesn’t mean it’s without problems. This is especially apparent when you do user research with people who are new to computing, including children and older people. Manually placing and sizing windows can be fiddly work, and requires close attention and precise motor control. It’s also what we jokingly refer to as shit work: it is work that the user has to do, which is generated by the system itself, and has no other purpose.
Most of the time you don’t care about exact window sizes and positions and just want to see the windows that you need for your current task. Often that’s just a single, maximized window. Sometimes it’s two or three windows next to each other. It’s incredibly rare that you need a dozen different overlapping windows. Yet this is what you end up with by default today, when you simply use the computer, opening apps as you need them. Messy is the default, and it’s up to you to clean it up.
What about tiling?
Traditional tiling window managers solve the hidden window problem by preventing windows from overlapping. While this works well in some cases, it falls short as a general replacement for stacked, floating windows. The first reason for this is that tiling window managers size windows according to the amount of available screen space, yet most apps are designed to be used at a certain size and aspect ratio. For example, chat apps are inherently narrow and end up having large amounts of empty space at large sizes. Similarly, reading a PDF in a tiny window is not fun.
Another issue with tiling window manager is that they place new windows in seemingly arbitrary positions. This is a consequence of them not having knowledge about the content of a window or the context in which it is being used, and leads to having to manually move or resize windows after the fact, which is exactly the kind of fiddling we want to avoid in the first place.
More constrained tiling window managers such as on iPadOS are interesting in that they’re more purposeful (you always intentionally create the tiling groups). However, this approach only allows tiling two windows side-by-side, and does not scale well to larger screens.
This topic has been of interest to the design team for a very long time. I remember discussing it with Jakub at my first GUADEC in 2017, and there have been countless discussions, ideas, and concepts since. Some particular milestones in our thinking were the concept work leading up to GNOME 40 in 2019 and 2020, and the design sessions at the Berlin Mini GUADEC in 2022 and the Brno hackfest in 2023.
I personally have a bit of a tradition working on this problem for at least a few weeks per year. For example, during the first lockdown in 2020 I spent quite a bit of time trying to envision a tiling-first version of GNOME Shell.
Problems with our current tiling
GNOME has had basic tiling functionality since early in the GNOME 3 series. While this is nice to have, it has obvious limitations:
It’s completely manual
Only 2 windows are supported, and the current implementation is not extensible to more complex layouts
Tiled windows are not grouped in the window stack, so both windows are not raised simultaneously and other windows get in the way
Workspaces are manual, and not integrated into the workflow
We’ve wanted more powerful tilingfor years, but there has not been much progress due to the huge amount of work involved on the technical side and the lack of a clear design direction we were happy with. We now finally feel like the design is at a stage where we can take concrete next steps towards making it happen, which is very exciting!
Get out of my way
The key point we keep coming back to with this work is that, if we do add a new kind of window management to GNOME, it needs to be good enough to be the default. We don’t want to add yet another manual opt-in tool that doesn’t solve the problems the majority of people face.
To do this we landed on a number of high level ideas:
Automatically do what people probably want, allow adjusting if needed
Make use of workspaces as a fully integrated part of the workflow
Richer metadata from apps to allow for better integration
Our current concept imagines windows having three potential layout states:
Mosaic, a new window management mode which combines the best parts of tiling and floating
Edge Tiling, i.e. windows splitting the screen edge-to-edge
Floating, the classic stacked windows model
Mosaic is the default behavior. You open a window, it opens centered on the screen at a size that makes the most sense for the app. For a web browser that might be maximized, for a weather app maybe only 700×500 pixels.
As you open more windows, the existing windows move aside to make room for the new ones. If a new window doesn’t fit (e.g. because it wants to be maximized) it moves to its own workspace. If the window layout comes close to filling the screen, the windows are automatically tiled.
You can also manually tile windows. If there’s enough space, other windows are left in a mosaic layout. However, if there’s not enough space for this mosaic layout, you’re prompted to pick another window to tile alongside.
You’re not limited to tiling just two windows side by side. Any tile (or the remaining space) can be split by dragging another window over it, and freely resized as the window minimum sizes allow.
There are always going to be cases that require placing a window in a specific position on the screen. The new system allows windows to be used with the classic floating behavior, on a layer above the mosaic/tiling windows. However, we think that this floating behaviour is going to be a relatively uncommon, similar to the existing “always on top” behavior that we have today.
There’s of course much more to this, but hopefully this gives an idea of what we have in mind in terms of behavior.
New window metadata
As mentioned above, to avoid the pitfalls of traditional tiling window managers we need more information from windows about their content. Windows can already set a fixed size and they have an implicit minimum size, but to build a great tiling experience we need more.
One important missing piece is having information on the maximum desired size of a window. This is the size beyond which the window content stops looking good. Not having this information is one of the reasons that traditional tiling window managers have issues, especially on larger screens. This maximum size would not be a hard limit and manual resizing would still be possible. Instead, the system would use the maximum size as one factor when it calculates an optimal window layout. For example, when tiling to the side of the screen, a window would only grow as wide as its maximum width rather than filling exactly half of the screen.
In addition, it’d be helpful to know the range of ideal sizes where an app works best. While an app may technically work at mobile sizes that’s probably not the best way to use that app if you have a large display. To stay with our chat example, you probably want to avoid folding the sidebar if it can be avoided, so the range of ideal sizes would be between the point where it becomes single pane and its maximum usable size.
Ideally these properties could be set dynamically depending on the window content. For example, a spreadsheet with a lot of columns but few rows could have a wider ideal size than one with lots of rows.
Depending on apps using new system APIs can be challenging and slow — it’s not easy to move the entire ecosystem! However, we think there’s a good chance of success in this case, due to the simplicity and universal usefulness of the API.
At the Brno hackfest in April we had an initial discussion with GNOME Shell developers about many of the technical details. There is tentative agreement that we want to move in the direction outlined in this post, but there’s still a lot of work ahead.
On the design side, the biggest uncertainty is the mosaic behavior — it’s a novel approach to window management without much prior art. That’s exciting, but also makes it a bit risky to jump head-first into implementation. We’d like to do user research to validate some of our assumptions on different aspects of this, but it’s the kind of project that’s very difficult to test outside of an actual prototype that’s usable day to day.
If you’d like to get involved with this initiative, one great way to help out would be to work on an extension that implements (parts of) the mosaic behavior for testing and refining the interactions. If you’re interested in this, please reach out :)
There’s no timeline or roadmap at this stage, but it’s definitely 46+ material and likely to take multiple cycles. There are individual parts of this that could be worked on independently ahead of the more contingent pieces, for example tiling groups or new window metadata. Help in any of these areas would be appreciated.
This post is summarizing collaborative work over the past years by the entire design team (Allan Day, Jakub Steiner, Sam Hewitt, et al). In particular, thanks to Jakub for the awesome animations bringing the behaviors to life!
Last week we had a small hackfest in Berlin, with a focus on making GNOME work better on mobile across the stack. We had about 15 people from various projects and backgrounds attending, including app developers, downstreams, hardware enablement, UX design, and more. In addition to hacking and planning sessions we also had some social events, and it was an opportunity to meet nice people from different corners of the wider community :)
The postmarketOS gang had their own hackfest over the weekend before ours, and on Monday we had the Cultivation Space venue for some chill random hacking. I wasn’t there for most of this, so I’ll let others report on it.
The main hackfest days were Tuesday and Wednesday, where we had an actual unconference agenda and schedule. We met at 11:30 in the morning at Cultivation Space and then managed to get through a surprisingly large list of topics very efficiently on both days. Kudos to Sonny for coming up with the format and moderating the schedule.
systemd and Image-Based OSes
On Tuesday Lennart from systemd stopped by for a bit, so we had a session with him and the postmarketOS people discussing integration issues, and a larger session about various approaches for how to do image-based OSes. It’s clear that this direction is the future — literally everyone is either doing it (Endless, Silverblue, GNOME OS, SUSE, Carbon OS, Vanilla OS) or wants to do it (PureOS, postmarketOS, elementaryOS). There are lots of different approaches being tried and nobody has the perfect formula for it yet, so it’s an exciting space to watch.
Edit: Clarification from postmarketOS: “We are looking into doing a version of postmarketOS that is image-based/has an immutable file system. But it will still be possible to use postmarketOS without it.”
I personally only half followed some of this while working on other stuff, but it was definitely interesting to hear people discuss the tradeoffs of the various approaches. For example, OSTree doesn’t support offline security which is why Lennart wants A/B/C partitions instead.
OS Stack Bake-Off
After this we had a big OS stack show and tell with people from Debian, GNOME OS, and postmarketOS. From a development/app platform point of view what we need is an OS with:
very recent kernel/hardware enablement (because most phones are still in the process of getting mainlined)
large, active community around the OS, including a security team
image-based, with Flatpak apps
up to date middleware (systemd, flatpak, portals, etc.)
release cycle in sync with GNOME’s
nightly images for testing/dogfooding
aligned with GNOME in terms of design philosophy (upstream first, design first, suitably scared of preferences, etc.)
Currently there isn’t an obvious best option, unfortunately. Debian/Mobian has a large community and recent kernels, but its stable version doesn’t have most of the other things we need since its release cycle is way too slow and out of sync with GNOME’s (and using testing/unstable has other problems). postmarketOS is doing lots of great work on hardware enablement and has a lot of what we want, but the lack of systemd makes it impractical (especially once we implement things like homed encryption). GNOME OS nominally has most of what we want, but the community around it is still too small and not enough people are using it full-time.
We’ll see what the future holds in this regard, but I’m hopeful that one or more options will tick all the boxes in the future!
Shell History and Discussion
Another point on the agenda was longer-term planning for the shell. The Phosh/GNOME Shell question has been unaddressed for years, and we keep investing tons of time and energy into maintaining two shells that implement the exact same design.
Unfortunately we didn’t have enough people from the Phosh side at the hackfest to do any actual planning, but we did discuss the history and current state of both projects. People also discussed next steps on the GNOME Shell mobile side, primarily making it clearer that the branch is maintained even though it’s not fully upstream yet, giving it a proper README, having an issue tracker, and so on.
Oliver was interested in MPRIS buttons, so we had a design session about it. The problem here is that different apps need different buttons in their MPRIS widget depending on the use case (e.g. podcast apps need jump buttons, pause doesn’t make much sense for a live stream, etc.). Currently we have no way for apps to tell the system what buttons it needs, so we discussed how this could be done. The results of our session are written up in this issue, and a vague consensus that this could be done as an extension of the existing MPRIS protocol.
To address the short-term issue of not having jump buttons for podcasts, Jonas statically added them to the mobile shell branch for now.
Pablo had encountered some oddities with the file opening pattern in his work on Evince, so we took a look at the question more broadly. Turns out we have a lot of different patterns for this, and almost every app behaves slightly differently! We didn’t get as far as defining if/how this could be standardized, but at least we wrote up the status quo and current use cases in apps in an issue.
Bart and Kolja from Flathub also joined on Monday and Tuesday, so we worked on the Flathub website a bit (primarily the app tile layout), and discussed a new initiative to make it possible to show the best apps on the home page. The current idea for this is to start off with a new toolbar on Flathub app pages when you’re logged in as a moderator, that allows a mods to set additional metadata on apps. We’d pair this with an outreach campaign to raise the bar on app metadata, and perhaps automated linting for some of the easier to check things.
Bart and Kolja also worked on finally getting the libappstream port done, so that we can have device support metadata, image captions, etc. from Flathub. They made a lot of good progress but this is still not quite done, because there’s lots of edge cases where the new system doesn’t work with some existing app metadata.
Mobile Platform Roadmap
A few of us sat down and worked on a priority list of things we’d need in GNOME mobile to be able to realistically daily drive it, including platform, shell, and app features. We documented the results in this issue.
Various other things that happened but that I didn’t follow closely:
Pablo and Sonny sat down together and looked over the postmarketOS GNOME session, doing a bit of QA and finding areas where it could be closer to the upstream GNOME vision. Lots of nice improvements since we last looked at it a few months back, and lots more to come :)
There was a session about device wakeup APIs. I didn’t attend it, but it sounded like they made progress towards a portal for this so that e.g. alarms can wake up the device when it’s suspended or powered off.
Robert, Dorota, Caleb, and others had several in-depth sessions on camera hardware enablement, libcamera and the like
Julian got GNOME OS running on the Librem 5 with a recent kernel
Overall I found the event very productive and a lot of fun, so thanks everyone for making it a success. In particular, thanks to the GNOME Foundation for sponsoring, Elio Qoshi and Cultivation Space for hosting us, and Sonny for co-organizing. See you next time!
Part 1 of this series looks at the state of the climate emergency we’re in, and how we can still get our governments to do something about it. Part 2 looks at collapse scenarios we’re likely to face if we fail in those efforts, and part 3 is about concrete things we could work towards to make our software more resilient in those scenarios. In this final part we’re looking at obstacles and contradictions on the path to resilience.
Part 3 of this series was, in large parts, a pretty random list of ideas for how to make software resilient against various effects of collapse. Some of those ideas are potentially contradictory, so in this part I want to explore these contradictions, and hopefully start a discussion towards a realistic path forward in these areas.
Efficient vs. Repairable
The goals of wanting software to be frugal with resources but also easy to repair are often hard to square. Efficiency is generally achieved by using lower-level technology and having developers do more work to optimize resource use. However, for repairability you want something high-level with short feedback loops and introspection, i.e. the opposite.
An app written and distributed as a single Python file with no external dependencies is probably as good as it gets in terms of repairability, but there are serious limitations to what you can do with such an app and the stack is not known for being resource-efficient. The same applies to other types of accessible programming environments, such as scripts or spreadsheets. When it comes to data, plain text is very flexible and easy to work with (i.e. good for repairability), but it’s less efficient than binary data formats, can’t be queried as easily as a database, etc.
My feeling is that in many cases it’s a matter of choosing the right tradeoffs for a given situation, and knowing which side of the spectrum is more important. However, there are definitely examples where this is not a tradeoff: Electron is both inefficient and not very repairable due to its complexity.
What I’m more interested in is how we could bring both sides of the spectrum closer together: Can we make the repair experience for a Rust app feel more like a single-file Python script? Can we store data as plain text files, but still have the flexibility to arbitrarily query them like a database?
As with all degrowth discussions, there’s also the question whether reducing the scope of what we’re trying to achieve could make it much easier to square both goals. Similar to how we can’t keep using energy at the current rate and just swap fossil fuels out for renewables, we might have to cut some features in the interest of making things both performant and repairable. This is of course easier said than done, especially for well-established software where you can’t easily remove things, but I think it’s important to keep this perspective in mind.
File System vs. Collaboration
If you want to store data in files while also doing local-first sync and collaboration, you have a choice to make: You can either have a global sync system (per-app or system wide), or a per-file one.
Global sync: Files can use standard formats because history, permissions for collaboration, etc. are managed globally for all files. This has the advantage that files can be opened with any editor, but the downside is that copying them elsewhere means losing this metadata, so you can no longer collaborate on the file. This is basically what file sync services à la Nextcloud do (though I’m not sure to what degree these support real-time collaboration).
Per-file sync: The alternative is having a custom file format that includes all the metadata for history, sync, and collaboration in addition to the content of the file. The advantage of this model is that it’s more flexible for moving files around, backing them up, etc. because they are self-contained. The downside is that you lose access to the existing ecosystem of editors for the file type. In some cases that may be fine because it’s a novel type of content anyway, but it’s still not great because you want to ensure there are lots of apps that can read your content, across all platforms. The Fullscreen whiteboard app is an example of this model.
Of course ideally what you’d want is a combination of both: Metadata embedded in each file, but done in such a way that at least the latest version of the content can still be opened with any generic editor. No idea how feasible that’d be in general, but for text-based formats I could imagine this being a possibility, perhaps using some kind of front-matter with a bunch of binary data?
More generally, there’s a real question where this kind of real-time collaboration is needed in the first place. For which use cases is the the ability to collaborate in real time worth the added complexity (and hence reduced repairability)? Perhaps in many cases simple file sync is enough? Maybe the cases where collaboration is needed are rare enough that it doesn’t make sense to invest in the tech to begin with?
Bandwidth vs. Storage
In thinking about building software for a world with limited connectivity, it’s generally good to cache as much as possible on disk and hit the network as little as possible. But of course that also means using more disk space, which can itself become a resource problem, especially in the case of older computers or mobile devices. This would be accelerated if you had local-first versions of all kinds of data-heavy apps that currently only work with a network connection (e.g. having your entire photo and music libraries stored locally on disk).
One potential approach could be to also design for situations with limited storage. For example, could we prioritize different kinds of offline content in case something has to be deleted/offloaded? Could we offload large, but rarely used content or apps to external drives?
For example, I could imagine moving extra Flatpak SDKs you only need for development to a separate drive, which you only plug in when coding. Gaming could be another example: Your games would be grayed-out in the app grid unless you plug in the hard drive they’re on.
Having properly designed and supported workflows and failure states for low-storage cases like these could go a long way here.
Perhaps you’re wondering why I’m writing about this topic in the context of free software, and GNOME in particular. Beyond the personal need to contextualize my own work in the reality of the climate crisis, I think there are two important reasons: First, free software may have an important role to play in keeping computers useful in coming crisis scenarios, so we should make sure it’s good at filling that role. GNOME’s position in the GNU/Linux space and our close relationships and personnel overlap with projects up and down the stack make it a good forum to discuss these questions and experiment with solutions.
But secondly, and perhaps more importantly, I think this community has the right kinds of people for the problems at hand. There aren’t very many places where low-level engineering and principled UX design are done together at this scale, in the commons.
Some resilience-focused projects are built on the very un-resilient web stack because that’s what the authors know. Others have a tiny community of volunteer developers, making it difficult to build something that has impact beyond isolated experiments. Conversely, GNOME has a large community of people with expertise all across the stack, making it an interesting place to potentially put some of these ideas into practice.
People to Learn From?
While it’s still quite rare in tech circles overall, there are some other people thinking about computing from a climate collapse point of view, and/or working on adjacent problems. While most of this work is not directly relevant to GNOME in terms of technology, I find some of the ideas and perspectives very valuable, and maybe you do as well. I definitely recommend following some of these people and projects on Mastodon :)
Permacomputing is a philosophy trying to apply permaculture-like principles to computing. The term was coined by Ville-Matias “Viznut” Heikkilä in a 2020 essay. Permaculture aims to establish natural systems that can work sustainably in the long term, and the goal with permacomputing is to do something similar for computing, by rethinking its relationship to resource and energy use, and the kinds of things we use it for. As further reading, I recommend this interview with Heikkilä and Marloes de Valk.
100 Rabbits is a two-person art collective living on a sailboat and experimenting with ideas around resilience, wherein their boat studio setup is a kind of test case for the kinds of resource constraints collapse might bring. One of their projects is uxn, a tiny, portable emulator, which serves as a super-constrained platform to build apps and games for in a custom Assembly language. I think their projects are especially interesting because they show that you don’t need fancy hardware to build fun, attractive things – what’s far more important is the creativity of the people doing it.
Collapse OS is an operating system written in Forth by Virgil Dupras for a further-away future, where industrial society has not only collapsed, but when people stop having access to any working modern computers. For that kind of scenario it aims to provide a simple OS that can run on micro-controllers that are easy to find in all kinds of electronics, in order to build or repair custom electronics and simple computers.
Low Tech is an approach to technology that tries to keep things simple and resilient, often by re-discovering older technologies and recombining them in new ways. An interesting example of this philosophy in both form and content is Low Tech Magazine (founded in 2007 by Kris De Decker). Their website uses a dithered aesthetic for images that allows them to be just a few Kilobytes each, and their server is solar-powered, so it can go down when there’s not enough sunlight.
p2panda is a protocol for building local-first apps. It aims to make it easy enough to build p2p applications that developers can spend their time thinking about interesting user experiences rather than focus on the basics of making p2p work. It comes with reference implementations in Rust and Typescript.
Earthstar is a local-first sync system developed by Sam Gwilym with the specific goal to be “like a bicycle“, i.e. simple, reliable, and easy enough to understand top-to-bottom to be repairable.
Unfortunately, as with all the most important work, it’s hard to get funding for projects in this area. It’ll take tons of work by very skilled people to make serious progress on things like power profiling, local-first sync, or mainlining Android phones. And of course, the direction is one where we’re not only not enabling new opportunities for commerce, but rather eliminating them. The goal is to replace subscription cloud services with (free) local-first ones, and make software so efficient that there’s no need to buy new hardware. Not an easy sell to investors :)
However, while it’s difficult to find funding for this work it’s not impossible either. There are a number of public grant programs that fund projects like these regularly, and where resilience projects around GNOME would fit in well.
If you’re based in the the European Union, there are a number of EU funds under the umbrella of the Next Generation Internet initiative. Many of them are managed by dutch nonprofit NLNet, and have funded a number of different projects with a focus on peer-to-peer technology, and other relevant topics. NLNet has also funded other GNOME-adjacent projects in the past, most recently Julian’s work on the Fractal Matrix client.
If you’re based in Germany, the German Ministry of Education’s Prototype Fund is another great option. They provide 6 month grants to individuals or small teams working on free software in a variety of areas including privacy, social impact, peer-to-peer, and others. They’ve also funded GNOME projects before, most recently the GNOME Shell mobile port.
The Sovereign Tech Fund is a new grant program by the German Ministry of Economic Affairs, which will fund work on software infrasctucture starting in 2023. The focus on lower-level infrastructure means that user-facing projects would probably not be a good fit, but I could imagine, for example, low-level work for local-first technology being relevant.
These are some grant programs I’m personally familiar with, but there are definitely others (don’t hesitate to reach out if you know some, I’d be happy to add them here). If you need help with grant applications for projects making GNOME more resilient don’t hesitate to reach out, I’d be happy to help :)
One of my hopes with this series was to open a space for a community-wide discussion on topics like degrowth and resilience, as applied to our development practice. While this has happened to some degree, especially at in-person gatherings, it hasn’t been reflected in our online discourse and actual day-to-day work as much as I’d hoped. Finding better ways to do that is definitely something I want to explore in 2023.
On the more practical side, we’ve had sporadic discussions about various resilience-related initiatives, but nothing too concrete yet. As a next step I’ve opened a Gitlab issue for discussion around practical ideas and initiatives. To accelerate and focus this work I’d like to do a hackfest with this specific focus sometime soon, so stay tuned! If you’d be interested in attending, let me know :)
It feels surreal to be writing this. There’s something profoundly weird about discussing climate collapse… on my GNOME development blog. Believe me, I’d much rather be writing about fancy animations and porting apps to phones. But such are the times. The climate crisis affects, or will affect, every aspect of our lives. It’d be more surreal not to think about how it will affect my work, to ignore or compartmentalize it as a separate thing.
Part 1 of this series looks at the state of the climate crisis, and how we can still get our governments to do something about it. Part 2 considers the collapse scenarios we’re likely to face if we fail in those efforts. In this part we’re looking at concrete things we could work towards to make our software more resilient in those scenarios.
The takeaway from part 2 was that if we fail to mitigate the climate crisis, we’re headed for a world where it’s expensive or impossible to get new hardware, where electrical power is scarce, internet access is not the norm, and cloud services don’t exist anymore or are largely inaccessible due to lack of internet.
What could we do to prepare our software for these risks? In this part of the series I’ll look at some ideas and relevant art for resilient technlogy, and how we could apply this to GNOME.
Producing power locally is comparatively doable given the right equipment, but internet access is contingent on lots of infrastructure both locally and across the globe. This is why reducing dependence on connectivity is probably the most important challenge for resilience.
Unfortunately we’ve spent the past few decades making software ever more reliant on having fast internet access, all the time. Manyof theapps people spend all day in are unusable without an internet connection. So what would be the opposite of that? Is anyone working in the direction of minimizing reliance on the network?
As it turns out, yes! It’s called “local-first”. The idea is that instead of the primary copy of your data being on a server and local apps acting as clients to it, the client is the primary source of truth. The network is only used optionally for syncing and collaboration, with potential conflicts automatically resolved using CRDTs. This allows for superior UX because you’re not waiting on the network, better privacy because you can end-to-end encrypt everything, and better handling of low-connectivity cases. All of this is of course technically very challenging, and there aren’t many implementations of it in production today, but the field is growing and maturing quickly.
Among the most prominent proponents of the local-first idea are the community around the Ink & Switch research lab and Muse, a sketching/knowledge work app for Apple platforms. However, there’s also prior work in this direction from the GNOME community: There’s Christian Hergert’s Bonsai, the Endless content apps, and it’s actually one of the GNOME Foundation’s newly announced goals to enable more people to build local-first apps.
automerge, a library for building local-first software
Fullscreen, a web-based whiteboard app which allows saving to a custom file format that includes history and editing permissions
Magic Wormhole, a system to send files directly between computers without any servers
Earthstar, a local-first sync system with USB support
Local-first often assumes it’s possible to sometimes use the network for syncing or transferring data between devices, but what if you never have an internet connection?
It’s possible to use the local network in some instances, but they’re not very reliable in practice. Local networks are often weirdly configured, and things can fail in many ways that are hard to debug (Source: Endless tried it and decided it was not worth the hassle). In contrast USB storage is reliable, flexible, and well-understood by most people, making it a much better fallback.
As a practical example, a photo management app built in this paradigm would
Store all photos locally so there’s never any spinners after first setup
Allow optionally syncing with other devices and collaborative album management with other people via local network or the internet
Automatically reconcile conflicts if something changed on other devices while they were disconnected
Allow falling back to USB, i.e. copying some of the albums to a USB drive and then importing them on another device (including all metadata, collaboration permissons, etc.)
Some concrete things we could work on in the local-first area:
Investigate existing local-first libraries, if/how they could be integrated into our stack, or if we’d need to roll our own
Prototype local-first sync in some real-world apps
Implement USB app installation and updates in GNOME Software (mockups)
While power can be produced locally, it’s likely that in the future it will be far less abundant than today. For example, you may only have power a few hours a day (already a reality in parts of the global south), or only when there’s enough sun or wind at the moment. This makes power efficiency in software incredibly important.
Power Measurement is Hard
Improving power efficiency is not straightforward, since it’s not possible to measure it directly. Measuring the computer’s power consumption as a whole is trivial, but knowing which program caused how much of it is very difficult to pin down (for more on this check out Aditya Manglik’s GUADEC talk (Recording on Youtube) about power profiling tooling). Making progress in this area is important to allow developers to make their software more power-efficient.
However, while better measurements would be great to have, in practice there’s a lot developers can do even without it. Power is in large part a function of CPU, GPU, and memory use, so reducing each of these definitely helps, and we do have mature profiling tools for these.
Choose a Low-Power Stack
Different tech stacks and dependencies are not created equal when it comes to power consumption, so this is a factor to take into account when starting new projects. One area where there are actual comparative studies on this is programming languages: For example, according to this paper Python uses way more power than other languages commonly used for GNOME app development.
Another important choice is user interface toolkit. Nowadays many applications just ship their own copy of Chrome (in the form of Electron) to render a web app, resulting in huge downloads, slow startup times, large CPU and memory footprints, and laggy interfaces. Using native toolkits instead of web technologies is a key aspect of making resilient software, and GTK4/Adwaita is actually in a really good position here given its performance, wide language support, modern feature set and widgets, and community-driven development model.
Schedule Power Use
It’s also important to actively consider the temporal aspect of power use. For example, if your power supply is a solar panel, the best time to charge batteries or do computing-intensive tasks is during the day, when there’s the most sunlight.
If we had a way for the system to tell apps that right now is a good/bad time to use a lot of power, they could adjust their behavior accordingly. We already do something similar for metered connections, e.g. Software doesn’t auto-download updates if your connection is metered. I could also imagine new user-facing features in this direction, e.g. a way to manually schedule certain tasks for when there will be more power so you can tell Builder to start compiling the long list of dependencies for a newly cloned Rust project tomorrow morning when the sun is back out.
Some concrete things we could work on in the area of resource efficiency:
Improve power efficiency across the stack
Explore a system API to tell apps whether now is a good time to use lots of power or not
Improve the developer story for GTK on Windows and macOS, to allow more people to choose it over Electron
In hedging against loss of connectivity, it’s not enough to have software that works offline. In many cases what’s more important is the data we read/write using that software, and what we can do with it in resource-constrained scenarios.
The File System is Good, Actually
The 2010s saw lots of experimentation with moving away from the file system as the primary way to think about data storage, both within GNOME and across the wider industry. It makes a lot of sense in theory: Organizing everything manually in folders is shit work people don’t want to do, so they end up with messy folder hierarchies and it’s hard to find things. Bespoke content apps for specific kinds of data, with rich search and layouts custom-tailored to the data are definitely a nicer, more human-friendly way to deal with content–in theory.
In practice we’ve seen a number of problems with the content app approach though, including
Flexibility: Files can be copied/pasted/deleted, stored on a secondary internal drive, sent as email attachments, shared via a USB key, opened/changed using other apps, and more. With content apps you usually don’t have all of these options.
Interoperability: The file system is a lowest common denominator across all OSes and apps.
Development Effort: Building custom viewers/editors for every type of content is a ton of work, in part because you have to reimplement all the common operations you get for free in a file manager.
Familiarity: While it’s messy and not that easy to learn, most people have a vague understanding of the file system by now, and the universality of this paradigm means it only has to be learned once.
Unmaintained Apps: Data living in a specific app’s database is useless if the app goes unmaintained. This is especially problematic in free software, where volunteer maintainers abandoning projects is not uncommon.
Due to the above reasons, we’ve seen in practice that the file system is not in fact dying. It’s actually making its way into places where it previously wasn’t present, including iPhones (which now come with a Files app) and the web (via Nextcloud, Google Drive, and company).
From a resilience point of view some of the shortcomings of content apps listed above are particularly important, such as the flexibility to be moved via USB when there’s no internet, and cross-platform interoperability. This is why I think user-accessible files should be the primary source of truth for user data in apps going forward.
Simple, Standardized Formats
With limited connectivity, a potential risk is that you don’t have the ability to download new software to open a file you’re encountering. This is why sticking to well-known standard formats that any computer is likely to have a viewer/editor for is generally preferable (plain text, standard image formats, PDF, and so on).
When starting a new app, ask yourself, is a whole new format needed or could it use/extend something pre-existing? Perhaps there’s a format you could use that already has an ecosystem of apps that support it, especially on other platforms?
For example, if you were to start a new notes app that can do inline media you could go with a custom binary format and a database, but you could also go with Markdown files in a user-accessible folder. In order to get inline media you could use Textbundle, an extension to Markdown implemented by a number of other Markdown apps on other platforms, which basically packs the contained media into an archive together with the Markdown file.
Side note: I really want a nice GTK app that supports Textbundle (more specifically, its compressed variant Textpack), if you want to make one I’d be deligthed to help on the design side :)
Export as Fallback
Ideally data should be stored in standardized formats with wide support, and human-readable in a text editor as a fallback (if applicable). However, this isn’t possible in every case, for example if an app produces a novel kind of content there are no standardized formats for yet (e.g. a collaborative whiteboard app). In these cases it’s important to make sure the non-standard format is well-documented for people implementing alternative clients, and has support for exporting to more common formats, e.g. exporting the current state of a collaborative whiteboard as PDF or SVG.
Some concrete things we could work on towards better data resilience:
Explore new ways to do content apps with the file system as a backend
Look at where we’re using custom formats in our apps, and consider switching to standard ones
Consider how this fits in with local-first syncing
Keep Old Hardware Running
There are many reasons why old hardware stops being usable, including software built for newer, faster devices becoming too slow on older ones, vendors no longer providing updates for a device, some components (especially batteries) degrading with use over time, and of course planned obsolescence. Some of these factors are purely hardware-related, but some also only depend on software, so we can influence them.
Use old Hardware for Development
I already touched on this in the dedicated section above, but obviously using less CPU, RAM, etc. helps not only with power use, but also allows the software to run on older hardware for longer. Unfortunately most developers use top of the line hardware, so they are least impacted by inefficiencies in their personal use.
One simple way to ensure you keep an eye on performance and resource use: Don’t use the latest, most powerful hardware. Maybe keep your old laptop for a few years longer, and get it repaired instead of buying a new one when something breaks. Or if you’re really hardcore, buy an older device on purpose to use as your main machine. As we all know, the best way to get developers to care about something is to actually dogfood it :)
Hardware Enablement for Common Devices
In a world where it’s difficult to get new hardware, it’ll become increasingly important to reuse existing devices we have lying around. Unfortunately, a lot of this hardware is stuck on very old versions of proprietary software that are both slow and insecure.
With Windows devices there’s an easy solution: Just install an up-to-date free software OS. But while desktop hardware is fairly well-supported by mainline Linux, mobile is a huge mess in this regard. The Android world almost exclusively uses old kernels with lots of non-upstreamable custom patches. It takes years to mainline a device, and it has to be done for every device.
Projects like PostmarketOS are working towards making more Android devices usable, but as you can see from their device support Wiki, success is limited so far. One especially problematic aspect from a resilience point of view is that the devices that tend to be worked on are the ones that developers happen to have, which are generally not the models that sell the most units. Ideally we’d work strategically to mainline some of the most common devices, and make sure they actually fully work. Most likely that’d be mid-range Samsung phones and iPhones. For the latter there’s curiously little work in this direction, despite being a gigantic, relatively homogeneous pool of devices (for example, there are 224 million iPhone 6 out there which don’t get updates anymore).
Unfortunately, hardware enablement alone is not enough to make old mobile devices more long-lived by installing more up-to date free software. Most mobile devices come with locked bootloaders, which require contacting the manufacturer to get an unlock code to install alternative software – if they allow it at all. This means if the vendor company’s server goes away or you don’t have internet access there’s no way to repurpose a device.
What we’d probably need is a collection of exploits that allow unlocking bootloaders on common devices in a fully offline way, and a user-friendly automated unlocking tool using these exploits. I could imagine this being part of the system’s disk utility app or a separate third-party app, which allows unlocking the bootloader and installing a new OS onto a mobile device you plug in via USB.
Some concrete things we could work on to keep old hardware running:
Actively try to ensure older hardware keeps working with new versions of our software (and ideally getting faster with time rather than slower thanks to ongoing performance work)
Explore initiatives to do strategic hardware eneblament for some of the most common mobile devices (including iPhones, potentially?)
Forge alliances with the infosec/Android modding community and build convenient offline bootloader unlocking tools
Build for Repair
In a less connected future it’s possible that substantial development of complex systems software will stop being a thing, because the necessary expertise will not be available in any single place. In such a scenario being able to locally repair and repurpose hardware and software for new uses and local needs is likely to become important.
Repair is a relatively clearly defined problem space for hardware, but for software it’s kind of a foreign concept. The idea of a centralized development team “releasing” software out into the world at scale is built into our tools, technologies, and culture at every level. You generally don’t repair software, because in most cases you don’t even have the source code, and even if you do (and the software doesn’t depend on some server component) there’s always going to be a steep learning curve to being able to make meaningful changes to an unfamiliar code base, even for seasoned programmers.
In a connected world it will therefore always be most efficient to have a centralized development team that maintains a project and makes releases for the general public to use. But with that possibly no longer an option in the future, someone else will end up having to make sure things work as best they can at the local level. I don’t think this will mean most people will start making changes to their own software, but I could see software repair becoming a role for specialized technicians, similar to electricians or car mechanics.
How could we build our software in a way that makes it most useful to people in such a future?
Use Well-Understood, Accessible Tech
One of the most important things we can do today to make life easier for potential future software repair technicians is using well-established technology, which they’re likely to already have experience with. Writing apps in Haskell may be a fun exercise, but if you want other people to be able to repair/repurpose them in the future, GJS is probably a better option, simply because so many more people are familiar with the language.
Another important factor determining a technology stack’s repairability is how accessible it is to get started with. How easy is it for someone to get a development environment up and running from scratch? Is there good (offline) documentation? Do you need to understand complex math or memory management concepts?
Most modern development workflows assume a fast internet connection on a number of levels, including downloading and updating dependencies (e.g. npm modules or flatpak SDKs), documentation, tutorials, Stackoverflow, and so on.
In order to allow repair at the local level, we also need to rethink development workflows in a local-first fashion, meaning things like:
Ship all the source code and development tools needed to rebuild/modify the OS and apps with the system
Have a first-class flow for replacing parts of the system or apps with locally modified/repaired versions, allowing easy management of different versions, rollbacks, etc.
Have great offline documentation and tutorials, and maybe even something like a locally cached subset of Stackoverflow for a few technologies (e.g. the 1000 most popular questions with the “gtk” tag)
Getting the tooling and UX right for a fully integrated local-first software repair flow will be a lot of work, but there’s some interesting relevant art from Endless OS from a few years back. The basic idea was that you transform any app you’re running into an IDE editing the app’s source code (thanks to Will Thompson for the screencast below). The devil is of course in the details for making this a viable solution to local software repair, but I think this would be a very interesting direction to explore further.
Some concrete things we could work on to make our software more repairable:
Avoid using obscure languages and technologies for new projects
Avoid overly complex and brittle dependency trees
Investigate UX for a local-first software repair flow
Revive or replace the Devhelp offline documentation app
Look into ways to make useful online resources (tutorials, technical blog posts, Stackoverflow threads, etc.) usable offline
This was part three of a four-part series. In the fourth and final installment we’ll wrap up the series by looking at some of the hurdles in moving towards resilience and how we could overcome them.
This is a lightly edited version of my GUADEC 2022 talk, given at c-base in Berlin on July 21, 2022. Part 1 briefly summarizes the horrors we’re likely to face as a result of the climate crisis, and why civil resistance is our best bet to still avoid some of the worst-case scenarios. Trigger Warning: Very depressing facts about climate and societal collapse.
While I think it’s critical to use the next few years to try and avert the worst effects of this crisis, I believe we also need to think ahead and consider potential failure scenarios.
What would it mean if we fail to force our governments to enact the necessary drastic climate action, both for society at large but also very concretely for us as free software developers? In other words: What does collapse mean for GNOME?
In researching the subject I discovered that there’s actually a discipline studying questions like this, called “Collapsology”.
Collapsology studies the ways in which our current global industrial civilization is fragile and how it could collapse. It looks at these systemic risks in a transdisciplinary way, including ecology, economics, politics, sociology, etc. because all of these aspects of our society are interconnected in complex ways. I’m far from an expert on this topic, so I’m leaning heavily on the literature here, primarily Pablo Servigne and Raphaël Stevens’ book “How Everything Can Collapse” (translated from the french original).
So what does climate collapse actually look like? What resources, infrastructure, and organizations are most likely to become inaccessible, degrade, or collapse? In a nutshell: Complex, centralized, interdependent systems.
There are systems like that in every part of our lives of course, from agriculture, to pharma, to energy production, and of course electronics. Because this talk’s focus is specifically the impact on free software, I’ll dig deeper on a few areas that affect computing most directly: Supply chains, the power grid, the internet, and Big Tech.
As we’ve seen repeatedly over the past few years, the supply chains that produce and transport goods across the globe are incredibly fragile. During the first COVID lockdowns it was toilet paper, then we got the chip shortage affecting everything from Play Stations to cars, and more recently a baby formula shortage in the US, among others. To make matters worse, many industries have moved to just-in-time manufacturing over the past decades, making them even less resilient.
Now add to that more and more extreme natural disasters disrupting production and transport, wars and sanctions disrupting trade, and financial crises triggered or exacerbated by some of the above. It’s not hard to imagine goods that are highly dependent on global supply chains becoming prohibitively expensive or just impossible to get in parts of the world.
Computers are one of the most complex things manufactured today, and therefore especially vulnerable to supply chain disruption. Without a global system of resource extraction, manufacturing, and trade there’s no way we can produce chips anywhere near the current level of sophistication. On top of that chip supply chains are incredibly centralized, with most of global chip production being controlled by a single Taiwanese company, and the machines used for that production controlled by a single Dutch company.
Access to an unlimited amount of power, at any time, for very little money, is something we take for granted, but probably shouldn’t. In addition to disruptions by extreme weather events one important factor here is that in an ever-hotter world, air conditioning starts to put an increasing amount of strain on the power grid. In parts of the global south this is one of the reasons why power outages are a daily occurrence, and having power all the time is far from guaranteed.
In order to do computing we of course need power, not only to run/charge our own devices, but also for the data centers and networking infrastructure running a lot of the things we’re connecting to while using those devices.
Which brings us to our next point…
Having a reliable internet connection requires a huge amount of interconnected infrastructure, from undersea cables, to data centers, to the local cable infrastructure that goes to your neighborhood, and ultimately your router or a nearby cellular tower.
All of this infrastructure is at risk of being disrupted by sea level rise and extreme weather, taken over by political actors wanting to control the flow of information, abandoned by companies when it becomes unprofitable to operate in a certain area due to frequent extreme weather, and so on.
Finally, at the top of the stack there’s the actual applications and services we use. These, too, have become ever more centralized and fragile at all levels over the past decades.
At the most basic level there’s OS updates and app stores. There are billions of iOS devices out there that are literally unable to get security updates or install new software if they lose access to Apple’s servers. Apple collapsing seems unlikely in the short term, but, for example, what if they stop doing business in your country because ofsanctions?
We used to warn about lock-in to proprietary software and formats, but at least Photoshop CS2 continues to run on your computer regardless of what happens to the company. With Figma et al you can not only not access your existing files anymore if the server isn’t accessible, you can’t even create new ones.
In order to get a few nice sharing and collaboration features people are increasingly just running all software in the cloud on someone else’s computer, whether it’s Google Slides for presentations, SketchUp for 3D modeling, Notion for note taking, Figma for design, and even games via game streaming services like Stadia.
From a free software perspective another particularly risky point of corporate centralization is Github, given that a huge number of important projects are hosted there. Even if you’re not actively using it yourself for development, you’re almost certainly depending on other projects hosted on Github. If something were to happen to it… yikes.
So to summarize, this is a rough outline of a potential failure scenario, as applied to computing:
No new hardware: It’s difficult and expensive to get new devices because there’s little to no new ones being made, or they’re not being sold where you live.
Limited power: There’s power some of the time, but only a few hours a day or when there’s enough sun for your solar panels. It’s likely that you’ll want to use it for more important things than powering computers though…
Limited connectivity: There’s still a kind of global internet, but not all countries have access to it due to both degraded infrastructure and geopolitical reasons. You’re able to access a slow connection a few times a month, when you’re in another town nearby.
No cloud: Apple and Google still exist, but because you don’t have internet access often enough or at sufficient speeds, you can’t install new apps on your iOS/Android devices. The apps you do have on them are largely useless since they assume you always have internet.
This may sound like an unrealistically dystopian scenario, until you realize: Parts of the global south are experiencing this today. Of course a collapse of these systems at the global level would have a lot of other terrible consequences, but I think seeing the global south as a kind of preview of where everyone else is headed is a helpful reference point.
A Smaller World
The future is of course impossible to predict, but in all likelihood we’re headed for a world where everything is a lot more local, one way or the other. Whether by choice (to reduce emissions and be more resilient), or through a full-on collapse, our way of life is going to change drastically over the next decades.
The future we’re looking at is likely to be a lot more disconnected in terms of the movement of goods, people, as well as information. This will necessitate producing things locally, with whatever resources are available locally. Given the complexity of most supply chains, this means many things we build today probably won’t be produced at all anymore, so there will need to be a lot more repair, and a lot less consumption.
Above all though, this will necessitate much stronger communities at the local level, working together to keep things running and make life liveable in the face of the catastrophes to come.
To be Clear: Fuck Nazis
When discussing apocalyptic scenarios like these I think a lot of people’s first point of reference is the Hollywood version of collapse – People out for themselves, fighting for survival as rugged individuals. There are certain types of people attracted by that who hold other reprehensible views, so when discussing topics like preparing for collapse it’s important to distance oneself from them.
That said, individual prepping is also not an effective strategy, because real life is not a Hollywood movie. In crisis scenarios mutual aid is just as natural a response for people as selfishness, and it’s a much better approach to actually survive longer-term. Resilient communities of people helping each other is our best bet to withstand whatever worst case scenarios might be headed our way.
We’ll Still Need Computers…
If this future comes to pass, how to do computing will be far from our biggest concern. Having enough food, drinkable water, and other necessities of life are likely to be higher on our priority list. However, there will definitely be important things that we will need computers for.
The thing to keep in mind here is that we’re not talking about the far future here: The buildings, roads, factories, fields, etc. we’ll be working with in this future are basically what we have today. The factories where we’re currently building BMWs are not going away overnight, even if no BMWs are being built. Neither are the billions of Intel laptops and mid-range Android phones currently in use, even if they’ll be slow and won’t get updates anymore.
So what might we need computers for in this hyper-local, resource-constrained future?
At the most basic level, a lot of our information is stored primarily on computers today, and using computers is likely to remain the most efficient way to access it. This includes everything from teaching materials for schools, to tutorials for DIY repairs, books, scientific papers, and datasheets for electronics and other machines.
The same goes for any kind of calculation or data processing. Computers are of course good at the calculations needed for construction/engineering (that’s kind of what they were invented for), but even things like spreadsheets, basic scripting, or accounting software are orders of magnitude more efficient than doing the same things without a computer.
We’re used to networking always meaning “access to the entire internet”, but that’s not the only way to do networks – Our existing computers are perfectly capable of talking to each other on a local network at the level of a building or town, with no connection to a global internet.
There are lots of examples of potential use cases for local-only networking and communication, e.g. city-level mesh networks, or low-connectivity chat apps like Briar.
Reuse, Repair, Repurpose
Finally, there’s a ton of existing infrastructure and machinery that needs computers in order to be able to run, be repaired, or repurposed, including farm equipment, medical devices, public transit, and industrial tools.
I’m assuming – but this is conjecture on my part, it’s really not my area of expertise – the machines we’re currently using to build cars and planes could be repurposed to make something more useful, which can actually still be constructed with locally available resources in this future.
…Running Free Software?
As we’ve already touched on earlier, the centralized nature of proprietary software means it’s inherently less resilient than free software. If the company building it goes away or doesn’t sell you the software anymore, there’s not much you can do.
Given all the risks discussed earlier, it’s possible that free software will therefore have a larger role in a more localized future, because it can be adapted and repaired at the local level in ways that are impossible with proprietary software.
Assumptions to Reconsider?
However, while free software has structural advantages that make it more resilient than proprietary software, there are problematic aspects of current mainstream technology culture that affect us, too. Examples of assumptions that are pretty deeply ingrained in how most modern software (including free software) is built include:
Fast internet is always available, offline/low-connectivity is a rare edge case, mostly relevant for travel
New, better hardware is always around the corner and will replace the current hardware within a few years
Using all the resources available (CPU, storage, power, bandwidth) is fine
Assumptions like these manifest in many subtle ways in how we work and what we build.
Dependencies and Package Managers
Over the past decade language-specific package managers such as npm and crates.io have taken off in an unprecedented way, leading to software with larger and more complex dependency graphs than ever before. This is the dominant paradigm for building software today, newer languages all come with their own built-in package manager.
However, just like physical supply chains, more complex dependency graphs are also less resilient. More dependencies, especially with pinned versions and lack of caching between projects means huge downloads and long build times when building software locally, resulting in lots of bandwidth, power, and disk space being used. Fully offline development is basically impossible, because every project you build needs to download its own specific version of every dependency.
It’s possible to imagine some kind of cross-project shared local dependency cache for this, but to my knowledge no language ecosystem is doing this by default at the moment.
Core parts of the software development workflow are increasingly moving to web-based tools, especially around code forges like Github or Gitlab. Issue management, merge requests, CI, releases, etc. all happen on these platforms, which are primarily or exclusively used via very, very, slow websites. It’s hard to overstate this: Code forges are among the slowest, shittiest websites out there, basically unusable unless you have a fast connection.
This is, of course, not resilient at all and a huge problem given that we rely on these tools for many of our key workflows.
Cloud Storage & Streaming
As already discussed relying on data centers is problematic on a number of levels, but in practice most people (even in the free software community), have embraced cloud services in some areas, at least at a personal level.
Instead of local photo, music, and movie collections many of us just use Google Photos, Spotify, and Netflix nowadays, which of course affects which kinds of apps are being built. For example, there are no modern, actively developed apps to manage your photo collection locally anymore, but we do have a nice, modern Spotify client…
Global Community Without the Internet?
Scariest of all, I think, is imagining free software development without the internet. This movement came into existence and grew alongside the global internet in the 80s and 90s, and it’s almost impossible to imagine what it could look like without it.
Maybe the movement as a whole, as well as individual projects would splinter into smaller, local versions in the regions that are still connected? But would there be a sufficient amount of expertise in each of those regions? Would development at any real scale just stop, and instead people would only do small repairs to what they have at the local level?
I don’t have any smart answers here, but I believe it’s something we really ought to think about.
This was part two of a four-part series. In part 3 we’ll look at concrete ideas and examples of things we can work towards to make our software more resilient.
This is a lightly edited version of my GUADEC 2022 talk, given at c-base in Berlin on July 21, 2022. Trigger Warning: Very depressing facts about climate and societal collapse.
In this community I’m primarily known for my work as a designer, but if you know me a bit better you’re aware that I also do a different kind of activism, which sometimes looks like this:
This was an Extinction Rebellion action in Berlin earlier this year, the week the new IPCC report was released. Among other things, the report says that keeping global warming to within 1.5 degrees, the goal all our governments agreed to, is basically impossible at this point.
The idea with this action in particular was to force the state to symbolically destroy the 1.5 degree goal in order to clear our street blockade. Here’s the police doing that:
It’s Happening Now
The climate crisis is no longer a thing future generations will one day have to deal with, like we were told as kids. It’s here, affecting all of us today, including in the global north. Some of the people travelling to this year’s Berlin Mini GUADEC were delayed by the massive heatwave, because train tracks on the way could not handle the heat.
Second-order consequences will include billions of people having to flee to less affected areas, which in turn will have almost unimaginable political consequences – If 5 million refugees from the Syrian civil war caused a Europe-wide resurgence in proto-fascist parties, what will 100 million or more do?
And that’s not the worst of it.
The climate system is not linear. There are a number of tipping elements which can, once destabilized, not be brought back to their previous state and go from being carbon sinks to actually releasing carbon into the atmosphere.
We don’t know which tipping points are reached at what temperature exactly, but past 2 degrees it’s very likely that we’ll cross enough of them to cause 4, 5, or more degrees of warming.
We Have 3 Years
While many terrible things can’t be avoided anymore, scientists tell us that we still have a “brief and rapidly closing window of opportunity” to avoid some of the worst consequences – If we manage to turn things around and start actually reducing emissions in the next few years, and then continue doing so over the following decades.
That doesn’t mean each of us individually deciding to buy organic food and bamboo toothbrushes – The individual carbon footprint was literally invented by BP to deflect responsibility from corporations onto people. It’s obviously important to reduce our emissions as much as possible individually (especially luxury emissions such as meat and air travel), but that should not be where we stop or invest most of our energy.
This political and economic system is clearly not capable of the kind of action needed to avert this crisis. However, we’re also not going to be able to build an entirely new system in the next few years, there’s just not enough time. We can either try to use the existing state regulatory apparatus to reduce emissions now, or accept collapse as inevitable.
That sounds incredibly bleak, and it is – but there really is still a path to turn this around, and there are people and movements with a plan. Depending on where you live they have different names, logos, and tactics, but the strategy is roughly the same:
Mass Mobilization: Organize a small part of the population (something like a single digit percentage) into a mass civil resistance movement, and generate awareness of the emergency in the broader population.
Civil Resistance: Use civil disobedience tactics to disrupt business, politics, and infrastructure and do enough economic damage that the government can’t ignore it.
Citizens’ Assemblies: Demand that the government give the power to decide how to respond to the climate crisis to Citizens’ Assemblies. Members of these assemblies are chosen at random, in a way that is representative of the population, and advised by scientific experts. The assemblies can then decide how to reduce emissions and mitigate the effects of the crisis in a way that is both effective and socially equitable, because they are not beholden to capital interests.
So in the face of this, should we all just drop everything and start doing blockades for the next few years?
Well, yes. If you’re not currently doing civil disobedience wherever you live, I’d recommend looking into what groups exist locally and joining them. Even if you’re not ready to glue yourself to the road, there’s plenty of stuff you can do to help. They need your support to succeed, and we all really need them to succeed.
If you’re based in or near Germany, there’s actually a great opportunity coming up for getting involved: There’s a big rebellion wave September 17-20, so now’s an ideal time to get in touch with a local group nearby, do an action training, and book the trip to Berlin! See you there ;)
This is the first part of a four-part series. In part 2 we’ll explore what happens if we don’t manage to force our governments to enact radical change in the next few years, and what that would mean concretely for free software.
Given the location of this year’s GUADEC many of us couldn’t make it to the real event (or didn’t want to because of the huge emissions), but since there’s a relatively large local community in Berlin and nearby central Europe, we decided to have a new edition of our satellite event, to watch the talks together remotely.
This year we were quite a few more people than last year (a bit more than 20 overall), so it almost had a real conference character, though the organization was a lot more barebones than a real event of course.
Thanks to Sonny Piers we had c-base as our venue this year, which was very cool. In addition to the space ship interior we also had a nice outside area near the river we could use for COVID-friendly hacking.
We also had a number of local live talks streamed from Berlin. Thanks to the people from c-base for their professional help with the streaming setup!
On Thursday I gave my talk about post-collapse computing, i.e. why we need radical climate action now to prevent a total catastrophe, and failing that, what we could do to make our software more resilient in the face of an ever-worsening crisis.
Unfortunately I ran out of time towards the end so there wasn’t any room for questions/discussion, which is what I’d been looking forward to the most. I’ll write it up in blog post form soon though, so hopefully that can still happen asynchronously.
Since Allan, Jakub, and I were there we wanted to use the opportunity to work on some difficult design questions in person, particularly around tiling and window management. We made good progress in some of these areas, and I’m personally very excited about the shape this work is taking.
Because we had a number of app maintainers attending we ended up doing a lot of hallway design reviews and discussions, including about Files, Contacts, Software, Fractal, and Health. Of course, inevitably there were also a lot of the kinds of cross-discipline conversations that can only happen in these in-person settings, and which are often what sets the direction for big things to come.
One area I’m particularly interested in is local-first and better offline support across the stack, both from a resilience and UX point of view. We never quite found our footing in the cloud era (i.e. the past decade) because we’re not really set up to manage server infrastructure, but looking ahead at a local-first future, we’re actually in a much better position.
Since GUADEC is hard to get to from Europe and some of us don’t do air travel, we’re going to do another edition of Berlin Mini GUADEC this year!
We have a pretty solid local community in Berlin these days, and there are a lot of other contributors living reasonably close by in and around central Europe. Last year’s edition was very fun and productive with minimal organizational effort, and this year will be even better!
Location and other details are TBA, but it’s going to be in Berlin during the conference and BoF days (July 20th to 25th).
Update: The location is C-Base (Rungestraße 20 in Kreuzberg, near U Jannowitzbrücke), and there’s now a Wiki page. Please add yourself to the attendee list so we get an idea how many people will be joining :)
GNOME 41 is going to be released in a few weeks, and as you may have heard it will come with a major refresh to Software’s interface.
Our goals for this initiative included making it a more appealing place to discover and install new apps, exposing app information more clearly, and making it more reliable overall. We’ve made big strides in all these areas, and I think you’ll be impressed how much nicer the app feels in 41.
There’s a lot of UI polish all across the app, including a cleaner layout for app cards, more consistent list views, a new simplified set of categories, a better layout for category pages, and much more.
Most of the groundwork for adaptiveness is also in place now. There are still a few views in need of additional tweaks, but for the most part the app is adaptive in 41.
However, the most visible change in this release is probably the near-complete overhaul of the app details pages. This includes a prettier header section, a more prominent screenshot carousel, and an all-new way of displaying app metadata.
Introducing Context Tiles
For the app details page we wanted to tackle a number of long-standing tricky questions about how to best communicate information about apps. These include:
Communicating app download size in a more nuanced way, especially for Flatpak apps where downloading additional shared runtimes may be required as part of installing an app
Showing the benefits of software freedom in a tangible way rather than just displaying the license
Making it clearer which files, devices, and capabilities apps have access to on the system
Incentivizing app developers to use portals rather than poking holes in the sandbox
Warning people about potential security problems
Providing information on whether the app will work on the current hardware (especially relevant for mobile)
Exposing age ratings more prominently and with more context
The solution we came up with is what we call context tiles. The idea is that each of these tiles provides the most important information about a given area at a glance, and clicking it opens a dialog with the full details.
The storage tile has two different states: When the app is not installed, it shows the download size of the app, as well as any additional required downloads (e.g. runtimes). When the app is installed it changes to show the size the app is taking up on disk.
The Safety tile combines information from a number of sources to give people an overall idea of how safe an app is to install and use.
At the most basic level this is about how technically secure an app is. Two important questions here are whether an app is sandboxed (i.e. whether it’s flatpaked or running on the host), and whether it uses Wayland.
However, even if an app is sandboxed it can still have unlimited access to e.g. your home folder or the webcam, if these are defined as static permissions in the Flatpak manifest.
While for some apps there is no alternative to this (e.g. IDEs are probably always going to need access to the file system), in many cases there are more secure portal APIs through which people can allow limited one-time access to various resources.
For example, if you switch an app from using the old GtkFileChooser to the portal-based GtkFileChooserNative you can avoid requiring a sandbox hole for the file system.
All of the above is of course a lot worse if the app also has internet access, since that can make security issues remotely exploitable and allows malicious apps to potentially exfiltrate user data.
While very important, sandboxing is not the entire story here though. Public auditability of the code is also very important for ensuring the security of an app, especially for apps which have a lot of permissions. This is also taken into consideration to assess the overall safety of an app, as a practical advantage of software freedom.
Folding all of these factors into a single rating at scale isn’t easy. I expect we’ll continue to iterate on this over the next few cycles, but I think what we have in 41 is a great step in the right direction.
With GNOME Mobile progressing nicely and large parts of our app ecosystem going adaptive it’s becoming more important to be able to check whether an app is adaptive before installing it. However, while adaptiveness is the most prominent use case for the hardware support tile at the moment, it’s not the only one.
The hardware support tile is a generic way to display which input and output devices an app supports or requires, and whether they match the currently available hardware. For example, this can also be used to communicate whether an app is fully keyboard-accessible or requires a gamepad.
Age ratings (via OARS) have been in Software for years, but we’ve wanted to present this information in a better way for some time.
The context tile we’re introducing in 41 shows the reasons for the rating at a glance, rather than just a rating.
The dialog shows more information on the exact types of content the app includes, though the current implementation is not quite the design we’d like here eventually. Due to technical constraints we currently list every single type of content and whether or not the app contains it, but ideally it would only show broad categories for things the app doesn’t contain. This will hopefully be improved next cycle to make the list easier to scan.
No matter how good an app store itself is, its appeal for people ultimately comes from the apps within it. Luckily GNOME has a sizable ecosystem of cool third party apps these days, exactly the kinds of apps people are looking to discover when they open Software.
However, not all of these apps look as good as they could in Software currently due to incomplete, outdated, or low quality metadata.
Additionally, Software 41 comes with some changes to how app metadata is presented (e.g. context tiles, larger screenshots), which make it more prominently visible than before.
This means now is the perfect moment to review and update your app metadata and make a new release ahead of the GNOME 41 release in a few weeks.
Lucky for you I already wrote a blog post walking you through the different kinds of metadata your app needs to really shine in Software 41. Please check it out and update your apps!
Software 41 was a real team effort, and I’d like to thank everyone who helped make it happen, especially Philip Withnall, Phaedrus Leeds, Adrien Plazas, and Milan Crha for doing most of the implementation work, but also Allan Day and Jakub Steiner for helping with various aspects of the design.
This is also a cool success story for cross-company upstream collaboration with people from Endless, Purism, and Red Hat all working together on an upstream-first product initiative. High fives all around!
Software 41 will be released with the rest of GNOME 41 in a few weeks, and it brings a number of changes to how app metadata is presented, including the newly added hardware support information, larger screenshots, more visible age ratings, and more.
If you haven’t updated your app’s metadata in a while this is the perfect moment to review what you have, update what’s missing, and release a new version ahead of the GNOME 41 release!
In this blog post I’ll walk you through the different kinds of metadata your app needs to really shine in Software 41, and best practices for adding it.
The app summary is a very short description that gives people an idea of what the app does. It’s often used in combination with the app name, e.g. on banners and app tiles.
In Software 41 we’re using the summary much more prominently than before, so it’s quite important for making your app look good. In particular, make sure to keep it short (we recommend below 35 characters, but the shorter the better), or it will look weird or be ellipsized.
Writing a good summary
The summary should answer the question “What superpower does this app give me?”. It doesn’t need to comprehensively describe everything the app does, as long as it highlights one important aspect and makes it clear why it’s valuable.
Some general guidance:
Keep it short (less than 35 characters)
Be engaging and make people curious
Use imperative if possible (e.g. “Browse the web” instead of “A web browser”)
Use sentence case
Things to avoid:
Technical details (e.g. the toolkit or programming language)
Structures like “GUI for X” or “Client for Y”
Mentioning the target environment (e.g. “X for GNOME”)
Repeating the app’s name
Overly generic adjectives like “simple”, “easy”, “powerful”, etc.
Articles (e.g. “A …” or “An …”)
Punctuation (e.g. a period at the end)
Title case (e.g. “Chat With Your Team”)
Maps: “Find places around the world”
Shortwave: “Listen to internet radio”
Byte: “Rediscover your music”
The app summary is set in your appdata XML file, and looks like this:
Hardware support metadata describes what kinds of input and output devices an app supports, or requires to be useful. This is a relatively recent addition to appstream, and will be displayed in Software 41 for the first time.
The primary use case for this at the moment is devices with small displays needing to query whether an app will fit on the screen, but there are all sorts of other uses for this, e.g. to indicate that an app is not fully keyboard-accessible or that a game needs a gamepad.
Appstream has a way for apps to declare what hardware they absolutely need (<require>), and things that are known to work (<recommends>). You can use these two tags in your appdata XML to specify what hardware is supported.
For screen size, test the minimum size your app can scale to and put that in as a requirement. The “ge” stands for “greater or equal”, so this is what you’d do if your app can scale to phone sizes (360px or larger):
Note: The appstream spec also specifies some named sizes (xsmall, small, large, etc.), which are broken and should not be used. It’s likely that they’ll be removed in the future, but for now just don’t use them.
If you want your app to make a good impression good screenshots are a must-have. This is especially true in 41, because screenshots are much larger and more prominent now.
Some general guidance for taking good app screenshots:
Provide multiple screenshots showing off the main areas of the app
Use window screenshots with a baked-in shadow (you can easily take them with Alt+PrintScr).
For apps that show content (e.g. media apps, chat apps, creative tools, file viewers, etc.) the quality of the example content makes the screenshot. Setting up a great screenshot with content takes a ton of time, but it’s absolutely worth it.
If you’re only doing screenshots in a single language/locale, use en-US.
Don’t force a large size if your app is generally used at small sizes. If the app is e.g. a small utility app a tiny window size is fine.
Before taking your screenshots make sure your system is using GNOME default settings. If your distribution changes these, an easy way to make sure they are all correct is to take them in a VM with Fedora, Arch, or something else that keeps to defaults. In particular, make sure you have the following settings:
System font: Cantarell
GTK stylesheet: Adwaita
System icons: Adwaita Icon Theme
Window controls: Close button only, on the right side
Things to avoid:
Fullscreen screenshots with no borders or shadow.
Awkward aspect ratios. Use what feels natural for the app, ignore the 16:9 recommendation in the appstream spec.
Huge window sizes. They make it very hard to see things in the carousel. Something like 800×600 is a good starting point for most apps.
Screenshots are defined in the appdata XML file and consist of an image and a caption which describes the image.
Like everyone else, I’m sad that we can’t have in-person conferences at the moment, especially GUADEC. However, thanks to the lucky/privileged combination of low COVID case numbers in central Europe over the summer, vaccines being available to younger people now, and a relatively large local community in and around Berlin we were able to put together a tiny in-person GUADEC satellite event.
Despite the somewhat different context we did a surprising number of classic GUADEC activities such as struggling to make it to the venue by lunchtime, missing talks we wanted to watch, and walking around forever to find food.
As usual we also did quite a bit of hacking (on Adwaita, Fractal, and Shell among other things), and had many interesting cross-domain discussions that rarely happen outside of physical meetups.
Thanks to Elio Qoshi and Onion Space for hosting, the GNOME Foundation for sponsoring, and everyone for attending. See you all at a real GUADEC next year, hopefully!
In the previous parts of this series (part 1, part 2, part 3, part 4) we looked at how power works within GNOME, and what this means for people wanting to have an impact in the project. An important takeaway was that the most effective way to do that is to get acquainted with the project’s ethos and values, and then working towards things that align with these.
However, you have to start somewhere. In practical terms, how do you do that?
Perhaps you have lots of big ideas and futuristic plans for the project, and your first impulse is to start working on those. However, if you’re a new contributor keep the following in mind:
There’s often important context and history around a subject that you may not be aware of yet. Having this context inform your ideas generally makes them better and easier for others to get on board with.
It’s important to build trust with the community. People are likely to be skeptical of super ambitious proposals from people they don’t know yet, and who may not stick around long term.
Learning to effectively advertise your ideas and get buy-in from various people takes time. This goes especially for bigger changes, e.g. ones which impact many different modules.
Ideally the size of the things you propose should be proportionate to how well-integrated into the community you are. Trying to do a complete rewrite of GNOME Shell as your first contribution is likely not going to result in much. Something simple and self-contained, such as an individual view in an app is usually a good place to get started.
This doesn’t mean newcomers shouldn’t dream big (I certainly did). However, realistically you’ll be more successful starting with small tasks and working your way up to larger ones as you gain a better understanding of the project’s history, the underlying technologies, and the interests of various stakeholders.
What exactly to do first depends on the area you’re planning on contributing to. I’ll keep this focused on the areas I’m personally most involved with and which have the most immediate impact on the product, but of course there are lots of other great ways to get involved, such as documentation, engagement, and localization.
For programming there is a newcomer guide that guides you towards your first merge request. Check out the developer portal for documentation and other resources. Beyond the newcomer projects you can of course also just look at open newcomer (and non-newcomer) issues in specific projects written in your language of choice on GNOME Gitlab.
For design it’s easiest to just reach out to the design team and ask them to help you find a good first task. Ideally you’d start working with developers on something real as soon as possible, and the design team usually know what urgently needs design at the moment.
Of course, if you’re a developer there’s also the option of starting out by writing your own third-party apps, rather than contributing to existing ones. A great third-party app is a very valuable contribution to the project, and with GNOME Circle there is a direct path to GNOME Foundation membership.
Becoming a part of the community is not just about doing work. It’s also about generally being active in community spaces, whether that’s hanging out in chat rooms, interacting with fellow contributors on social media, or going to physical meetups, hackfests, and conferences.
Some starting points for that:
Join the Matrix channels for the projects you’re interested in. Depending on the channel it’s possible that not much is going on at the moment, but this tends to be seasonal. Especially app-specific channels can fluctuate wildly in activity depending on how many people are working on the app right now.
Join some of the larger “general” GNOME Matrix channels for project-wide discussions and community stuff.
Reach out to people who work on things you want to get into and ask them about ways to get involved more closely. Of course it’s important to be respectful of people’s time, but most people I know are happy to answer a few quick questions once in a while.
Come to GUADEC, LAS, or other real-world meetups. Meeting other contributors face to face is one of the best ways to truly become part of the community, and it’s a lot of fun! Once it’s possible again COVID-wise, I highly recommend attending an in-person event.
Doing the Work
If you follow the above steps and contribute on a regular basis for a few months you’ll find that you’ve organically become a part of the project.
People will start to ask your opinion about what they’re currently doing, or for you to review their work. You’ll probably specialize in one or a few areas, and maybe become the go-to person for those things. Before you know it someone will ask you if you’re coming to the next hackfest, if you’ve already got your Foundation membership, or if you’d like to become co-maintainer of a module.
If you’ve joined the project with big ideas, this is the point where you can really start moving towards making those ideas a reality. Of course, making big changes isn’t easy even as a long-time contributor. Depending on the scope of an initiative it can take months or years to get something done (for example, our adaptive apps initiative started in 2018 and is still ongoing).
However, as an experienced contributor you have the technical, social, and ideological context to push for your ideas in a way that aligns with other people’s goals and motivations. This not only makes it less likely that your plans will face opposition, but if you’re doing it right it people will join you and help make it happen.
This concludes my 5-part series on how power works in the GNOME community, and how to get your pet feature implemented. Sorry to disappoint if you thought it was going to be quick and easy :)
On the plus side though, it’s a chance to be part of this amazing community. The friends you make along the way are truly worth it!
While this is the end of the series as I originally planned it, there are definitely areas it doesn’t cover and that I might write about in the future. If there are specific topics you’d be interested in, feel free to leave a comment.
In the first three parts of this series (part 1, part 2, part 3) we looked at how power works within GNOME and what that means for getting things done. We got to the point that to make things happen you (or someone you’ve hired) need to become a trusted member of the community, which requires understanding the project’s ethos.
In this post we’ll go over that ethos, both in terms of high level values, and what those translate to in more practical terms.
Values and Principles
GNOME is a very principled project, and there’s a fair amount of writing on this topic already.
To give you an overview though, here’s my personal bullet point summary. It follows the same structure as the development process laid out in part 2 based on what areas specific values and ideas apply to. It’s not meant to be comprehensive, but rather give you an idea of the way people inside the project think.
Base motivations that inform everything we do.
We believe in software freedom as an inclusive, accountable model for producing technology in the commons.
Our software is built to be usable by everyone. We care deeply about user experience, accessibility, internationalization, and support for a diverse range of hardware.
Software should be structurally and aesthetically elegant, both in terms of underlying technology and user interface.
What kinds of things we think are worth pursuing, and (just as important) what kinds of things should be avoided.
Third-party apps are the best abstraction to extend the core system with additional functionality. This is why we put a huge amount of work into empowering third party app developers to build more and better apps.
Every preference has a cost, and this cost rises exponentially as you add more of them. This is why we avoid preferences as much as possible, and focus on fixing the underlying problems instead.
Similarly, there is a direct relationship between how vertically integrated a product is and how cohesive you can make it. Every unnecessary variable you eliminate across the stack frees up time and energy, and creates opportunities for features you couldn’t otherwise build.
People’s attention is precious. We pride ourselves in being distraction free.
Useful rules of thumb around how we go about making things.
We don’t do hacks. Rather than working around a problem at the wrong layer of abstraction, we believe in going to the root of the problem and fixing it for everyone, even if that means digging into lower layers (and ends up being far more difficult as a result).
We see design holistically, rather than as an isolated thing the design team does. It’s not just about functionality and aesthetics, but also underlying technology, and what to build in the first place. Even if you’re not contributing on the design team, developing an affinity for design will make you a more effective contributor.
Looking at relevant art is important, but simply copying the competition doesn’t usually produce great results. We have a proud history of inventing new paradigms that are better than the status quo.
As a general rule, start from the user experience you want and then go about building the technology necessary to create it, not the other way around. However: This is not an excuse for bad engineering or pursuing ideas that are conceptually impossible (e.g. multi-protocol chat clients).
Defer to the Expert. Everyone has different areas of expertise, such as user experience, security, accessibility, performance, or localization. Listen to the people most experienced in a given domain.
Design is all about trade-offs. Be wary of hard and fast rules that only look at one part of a problem (e.g. “vertical space is at a premium, therefore…”), and instead try to balance various concerns in a way that works well overall.
Some of the above principles are quite abstract, so what do they translate to when actually building software day to day? Here are some examples of how they apply to real-world questions.
App developers should do their own packaging. It’s the only way to do it sustainably at scale.
The “traditional desktop” is dead, and it’s not coming back (Note: I’m talking about Windows 95 era UI patterns here, not desktop vs. mobile). Instead of trying to bring back old concepts like menu bars or status icons, invent something better from first principles.
System-wide theming is a broken idea. If you don’t like the way apps look, contribute to them directly (or to the platform style).
Shell extensions are always going to be a niche thing. If you want to have real impact your time is better invested working on apps or GNOME Shell itself.
“Filling the available space” is rarely a good goal by itself, and an easy way to design yourself into a corner.
All of the above is of course my personal perception, and you’ll find variations on these ideas depending on who you talk to. However, in my experience most of them are shared fairly consistently by people across the community, especially given our informal structure.
Now that we’ve covered how things get done, by whom, and why, you’re in a great position to start making your mark. In the next part of this series we’ll look at practical first steps for contributing.
In parts 1 and 2 of the series we looked at how different groups inside the GNOME community work together to get things done. In this post we’ll look at what that means for people wanting to push for their personal agenda, e.g. getting a specific feature implemented or bug fixed.
Implicit in the theoretical question how power works in GNOME is often a more practical one: How can I get access to it? How can I exercise power to get something I want?
At a high level that’s very easy to answer: You either do the work yourself, or you convince someone else to do it.
Do It Yourself
If you’re the person working on something you have a ton of power over that thing. Designing and building software is in essence an endless stream of decisions. The more work you do, the more of those decisions you end up making.
Of course, in practice it’s not quite that simple. User-visible features need design reviews, and unless you’re the sole maintainer of a project you also need to go through code reviews to get your changes merged. As a designer, most things you design need to be implemented by someone else, so you have to convince them to do that.
However, it’s definitely possible to have a huge impact simply by doing a lot of work, and not only because of all the decisions you end up making directly as you implement things. If you contribute regularly to a module you’ll eventually end up reviewing other people’s work, and generally being asked for your opinion on topics you’re knowledgeable about.
Making Your Case
If you can’t, don’t want to, or don’t have time to do the work yourself, you’ll need to find someone else to do it for you. This is obviously a difficult task, because you’re essentially trying to convince people to work for you for free.
Some general tips for this:
Get an idea of what kinds of things the people you’re trying to convince are interested in, e.g. technologies they like and types of problems they care about.
Make the case that your idea fits into something they are already working on, or will help them reach goals they are already pursuing.
Generally speaking, you’ll have a much better chance with new-ish contributors. They tend to be less overworked since they don’t maintain as many mission-critical modules.
Realistically, unless your idea is very small in scope, or exactly what someone was already looking for, this strategy is not very likely to succeed. Most contributors, volunteer or paid, already have a huge backlog of their own to work through. There are only so many hours in the day, and GtkTimeMachine is not yet a thing :)
However, the chances are not zero either, and it’s always possible that even if your idea isn’t picked up right away it will spark something later on, or influence future discussions.
Paying Someone Else
You can of course also convince people to work on something you want by hiring them (radical, I know!).
There are plenty of very talented people in the GNOME community who do contract development, from individuals to fairly large consultancies. You can also hire someone from outside the project, but then they will have to build trust with the community first, which is non-trivial overhead. In most cases, hiring existing contributors is orders of magnitude more effective than people who aren’t already a part of the project.
How to hire people to implement things for you is out of scope for this series, but if you’d like advice on it feel free to contact me or leave a comment. If there’s enough interest I might write about it in the future.
All of that said, if the thing you want doesn’t align with the ethos of the project it’s going to be difficult regardless of which strategy you go with. This is why familiarizing yourself with that ethos is important if you want to make your mark on the project. To help with that we’ll go over GNOME’s principles and values in the next part of this series.
In part 1 of this series we looked at some common misconceptions about how power works inside the GNOME project and went over the roles and responsibilites of various sub-groups.
With that in place, let’s look at how of a feature (or app, redesign, or other product initiative) goes from idea to reality.
At the base of everything are the motivations for why we embark on new product initiatives. These are our shared values, beliefs, and goals, rooted in GNOME’s history and culture. They include goals like making the system more approachable or empowering third party developers, as well as non-goals, such as distracting people or introducing unnecessary complexity.
Since people across the project generally already agree on these it’s not something we talk about much day-to-day, but it informs everything we do.
At any given moment there are potentially hundreds of equally important things people working on GNOME could do to further the project’s goals. How do we choose what to work on when nobody is in charge?
This often depends on relatively hard to predict internal and external factors, such as
A volunteer taking a personal interest in solving a problem and getting others excited about it (e.g. Alexander Mikhaylenko’s multi-year quest for better 1-1 touchpad gestures)
A company giving their developers work time to focus on getting a specific feature done upstream (e.g. Endless with the customizable app grid)
The design team coming up with something and convincing developers to make it happen (e.g. the Shell dialog redesign in 3.36)
A technological shift presenting a rare opportunity to get a long-desired feature in (e.g. the Libadwaita stylesheet refresh enabling recoloring)
For larger efforts, momentum is key: If people see exciting developments in an area they’ll want to get involved and help make it even better, resulting in a virtuous cycle. A recent example of this was GNOME 40, where lots of contributors who don’t usually do much GNOME Shell UI work pitched in during the last few weeks of the cycle to get it over the line.
If something touches more than a handful of modules (e.g. the app menu migration), the typical approach is to start a formal “Initiative”: This is basically a Gitlab issue with a checklist of all affected modules and information on how people can help. Any contributor can start an initiative, but it’s of course not guaranteed that others will be interested in helping with it and there are plenty of stalled or slow-moving ones alongside the success stories.
If a new app or feature is user-facing, the first step towards making it happen is to figure out the user experience we’re aiming for. This means that at some point before starting implementation the designers need to work through the problem, formulate goals, look at relevant art, and propose a way forward (often in the form of mockups). This usually involves a bunch of iterations, conversations with various stakeholders, and depending on the scale of the initiative, user research.
If the feature is not user-facing but has non-trivial technical implications (e.g. new dependencies) it’s good to check with some experienced developers or the release team whether it fits into the GNOME stack from a technical point of view.
Once there is a more or less agreed-upon design direction, the implementation can start. Depending on the size and scope of the feature there are likely additional design or implementation questions that require input from different people throughout the process.
When the feature starts getting to the point where it can be tested by others it gets more thorough design reviews (if it’s user facing), before finally being submitted for code review by the module’s maintainers. Once the maintainers are happy with the code, they merge it into the project’s main branch.
In the next installment we’ll look at what this power structure and development process mean for individual contributors wanting to work towards a specific goal, such as getting their pet bug fixed or feature implemented.
People new to the GNOME community often have a hard time understanding how we set goals, make decisions, assume responsibility, prioritize tasks, and so on. In short: They wonder where the power is.
When you don’t know how something works it’s natural to come up with a plausible story based on the available information. For example, some people intuitively assume that since our product is similar in function and appearance to those made by the Apples and Microsofts of the world, we must also be organized in a similar way.
This leads them to think that GNOME is developed by a centralized company with a hierarchical structure, where developers are assigned tasks by their manager, based on a roadmap set by higher management, with a marketing department coordinating public-facing messaging, and so on. Basically, they think we’re a tech company.
This in turn leads to things like
People making customer service style complaints, like they would to a company whose product they bought
General confusion around how resources are allocated (“Why are they working on X when they don’t even have Y?”)
Blaming/praising the GNOME Foundation for specific things to do with the product
If you’ve been around the community for a while you know that this view of the project bears no resemblance to how things actually work. However, given how complex the reality is it’s not surprising that some people have these misconceptions.
To understand how things are really done we need to examine the various groups involved in making GNOME, and how they interact.
The GNOME Foundation is a US-based non-profit that owns the GNOME trademark, hosts our Gitlab and other infrastructure, organizes conferences, and employs one full-time GTK developer. This means that beyond setting priorities for said GTK developer, it has little to no influence on development.
The people actually making the product are either volunteers (and thus answer to nobody), or work for one of about a dozen companies employing people to work on various parts of GNOME. All of these companies have different interests and areas of focus depending on how they use GNOME, and tend to contribute accordingly.
In practice the line between “employed” contributor and volunteer can be quite blurry, as many contributors are paid to work on some specific things but also additionally contribute to other parts of GNOME in their free time.
Each module (e.g. app, library, or system component) has one or more maintainers. They are responsible for reviewing proposed changes, making releases, and generally managing the project.
In theory the individual maintainers of each module have more or less absolute power over those modules. They can merge any changes to the code, add and remove features, change the user interface, etc.
However, in practice maintainers rarely make non-trivial changes without consulting/communicating with other stakeholders across the project, for example the design team on things related to the user experience, the maintainers of other modules affected by a change, or the release team if dependencies change.
The release team is responsible for coordinating the release of the entire suite of GNOME software as a single coherent product.
In addition to getting out two major releases every year (plus various point releases) they also curate what is and isn’t part of the core set of GNOME software, take care of the GNOME Flatpak runtimes, manage dependencies, fix build failures, and other related tasks.
The Release Team has a lot of power in the sense that they literally decide what is and isn’t part of GNOME. They can add and remove apps from the core set, and set system-wide default settings. However, they do not actually develop or maintain most of the modules, so the degree to which they can concretely impact the product is limited.
Perhaps somewhat unusually for a free software project GNOME has a very active and well-respected design team (If I do say so myself :P). Anything related to the user experience is their purview, and in theory they have final say.
This includes most major product initiatives, such as introducing new apps or features, redesigning existing ones, the visual design of apps and system, design patterns and guidelines, and more.
However: There is nothing forcing developers to follow design team guidance. The design team’s power lies primarily in people trusting them to make the right decisions, and working with them to implement their designs.
How do things get done then?
No one person or group ultimately has much power over the direction of the project by themselves. Any major initiative requires people from multiple groups to work together.
This collaboration requires, above all, mutual trust on a number of levels:
Trust in the abilities of people from other teams, especially when it’s not your area of expertise
Trust that other people also embody the project’s values
Trust that people care about GNOME first and foremost (as opposed to, say, their employer’s interests)
Trust that people are in it for the long run (rather than just trying to quickly land something and then disappear)
This atmosphere of trust across the project allows for surprisingly smooth and efficient collaboration across dozens of modules and hundreds of contributors, despite there being little direct communication between most participants.
This concludes the first part of the series. In part 2 we’ll look at the various stages of how a feature is developed from conception to shipping.
Windows XP was still everywhere. Smartphones were tiny, and not everyone had one yet. Newoperatingsystems were coming out left and right. Android phones had physical buttons, and webOS seemed to have a bright future. There was general agreement that the internet would bring about a better world, if only we could give everyone unrestricted access to it.
I can’t speak to what it was like inside the project back then, this is all way before my time. I was still in high school, and though I wasn’t personally contributing to any free software projects yet, I remember it being a very exciting moment.
3.0 was a turning point. It was a clear sign that we’d not only caught up to, but confidently overtaken the proprietary desktops. It was the promise that everything old and crufty about computing could be overcome and replaced with something better.
As an aspiring designer and free software activist it was incredibly inspiring to me personally, and I know I’m not alone in that. There’s an entire generation of us who are here because of GNOME 3, and are proud to continue working in that tradition.
I’ve written about designing GNOME apps at a high level before, but not about the actual process of drawing UI mockups the way we do on the GNOME design team. In this tutorial we’ll pick up the Read It Later example from previoustutorials again, and draw some mockups in Inkscape from scratch.
Before we start, let’s look at the sketches we’re going to base this on. I’ve re-drawn some of the sketches from my last app design blog post with just the parts we’ll need for this tutorial.
I recommend having a look at that other blog post before jumping into this one, as it will give you some background on the basic design patterns and show step by step how we got to this layout.
What’s in a Mockup?
After you’ve designed the basic structure of your app (e.g. as a sketch on paper) but before starting implementation, it’s good to check what your layout will look like with real UI elements.
This doesn’t mean mockups need to recreate every gradient and highlight from the GTK stylesheet. Doing that would make mockups very hard to edit and keep in sync as the stylesheet evolves. However, things like spacing, border radii, button styling, etc. can be made to look very close to how they’ll look in the implemented version with relatively little effort. This is why on the GNOME design team we use a simplified style somewhere between a wireframe and a mockup, where sizes and metrics are mostly pixel-perfect, but UI visuals are not.
This level of fidelity is great for trying variations on layouts, placement of individual controls, different icon metaphors, etc. which are the most important things to validate before starting development. Once the implementation is in progress there’s usually additional rounds of iteration on different aspects of the design, but those don’t always require mockups as you can just iterate directly in code at that point.
In order to be able to follow along with this tutorial, you’ll need to install a few apps:
Inkscape: The vector drawing app we’ll be using to draw our mockup
Icon Library: A handy app for finding symbolic icons to use in mockups
Next, you need the GNOME mockup template. This is an SVG file with many of our most common UI patterns, which enables you to make mockups by copying and adapting these existing components, rather than having to draw every element yourself. You can download the template from GNOME Gitlab.
Finally, you need a recent version of Cantarell, GNOME’s interface font. It’s possible that while you may have a font with that name installed, it’s not the right version, because some distributions and Google Fonts are still on an old version (which has only 2 weights, rather than 5). You can download the new version here.
If you’ve never used Inkscape before it might be good to do some more general beginner tutorials as a first step. I’ll assume familiarity with navigation and object manipulation primitives such as selection, moving/scaling/rotating, duplicating, manipulating z-index, grouping/ungrouping, and navigating through group hierarchies.
Nevertheless, here’s a quick overview of the features we’ll be using primarily.
Inkscape has a lot of features, but we only need a small subset for what we’re doing. Most interfaces are just nested rectangles, after all ;)
Toolbox (the toolbar on the left edge):
Selection/movement/scaling tool (S)
Rectangle tool (R)
Ellipse tool (E)
Text tool (T)
Color picker (D)
Properties Sidebar (configuration dialogs docked to the right side):
Fill & Stroke (Ctrl + Shift + F)
Align & Distribute (Ctrl + Shift + A)
Export (Ctrl + Shift + E)
Document Properties (Ctrl + Shift + D)
Snap Controls (the toolbar on the right edge): Inkscape has very fine-grained snapping controls to configure what should be snapped to when you move items on the canvas (e.g. path nodes, object center, path intersections). It’s a bit fiddly, but very useful for making sure things are aligned to the grid. The icon tooltips are your friends :)
When aligning things or working with the pixel grid it’s very helpful to have the page grid visible. It can be toggled with the # shortcut or in the View menu.
Advanced: Partial Rounded Corners
One sort of advanced thing I started doing recently is using path effects to get rounded corners only on specific corners of a rectangle. This is handy compared to having the rounding baked into the geometry, because it keeps the rounding flexible, so the object can be scaled without affecting the rounded corners.
The feature is quite hidden and looks very complex, but once you know where it is it’s not that scary. You can find it in Path > Path Effects... > + > Corners (Fillet/Chamfer).
You’ll find that the mockup templates use this path effect technique for e.g. rounded bottom corners on windows.
It’s not as important for mockups as it is for app icons, but still nice to have: The GNOME color palette. Inkscape 1.0+ includes it by default, so you can just choose it from the arrow menu on the right.
With that out of the way, let’s get started making our mockup! First, we need a basic page to start from. We can start from the empty-page.svg file, by opening that file and saving it under the name we’ll ultimately want for our mockup, e.g. read-later.svg.
GNOME mockups usually consist of one or more views laid out on a “page” of whatever size is needed to make the content fit. There’s usually a title and description at the top, plus additional captions to explain things about the individual screens where it’s needed (example).
The page dimensions can be adjusted in Document Properties (Ctrl + Shift + D). One useful shortcut here is Ctrl+Shift+R, which resizes to the bounding box of the current selection (Note: Only use this shortcut if the thing you’re resizing to is e.g. a rectangle you set up for that purpose. Resizing the page to things off the pixel grid will break it, because it moves the document origin).
Let’s do that, and tweak the title and description for our case:
Now that the page is set up we can add our first screen. This is the sketch we’re going to be drawing first:
As a first step, let’s bring in the window template with view switcher from pattern-templates.svg. Open that file in Inkscape, select the top leftmost screen, copy it, and paste it into your mockup file.
After roughly positioning the window, check the exact position using the numeric position entries in the bar at the top, and make sure both X and Y positions are full integers (if they’re not integers it means your mockup is off the pixel grid and will look blurry).
It’s worth pointing out that while in this case we’re just starting from the plain default templates, it’s often faster to start from an existing mockup for another app. The app-mockups repository on GNOME Gitlab is full of existing mockups to borrow elements from or use as a starting point for a new mockup. That said, depending on their age those mockups might be using outdated patterns, so it’s good to check when a particular mockup was last updated :)
Let’s start by adjusting the headerbar to what we have in our sketch. Conveniently, several of the buttons don’t need to change at all from the template. All we need to do here is move the search button to the left, delete the add button, and adjust the switcher.
As a general rule, spacing between elements is a multiple of 6 pixels (so 6, 12, 18, 24…). For example, there are 6px of padding around buttons inside a headerbar, and 6px between the individual buttons.
When moving/placing elements, always make sure that snapping to bounding box is active (topmost group of snapping controls). As with the placement of the window earlier, it’s good to verify that sizes and positions are even integers in the toolbar up top.
Next up: The view switcher. You can start by changing the three labels, and then re-centering the icon + label groups on their respective containers. The inactive items have invisible containers, so they’re a bit fiddly to select.
For the icons, you can fire up Icon Library and search for the following icons:
Archive: drawer *
* This icon isn’t included yet, but will be in a future version
You can paste icons directly into Inkscape using the “Copy to Clipboard” feature. Before pasting, navigate into the relevant icon group (each of the icons is grouped with an invisible 16px rectangle, because that’s the icon canvas size). When placing an icon, make sure to center it on the invisible canvas rectangle, and place them on the pixel grid. You may want to turn on outline mode (Ctrl+5 cycles through display modes) to deal with the invisible rectangles more easily.
Once the icons are replaced, change the label strings with the text tool, and move the icon+label blocks horizontally so they look centered within their containers. I personally just do this manually by eye rather than using the alignment tool, so I don’t lose the icon’s alignment to the pixel grid, but you can also align and then manually move it to the closest position on the pixel grid.
With this, the headerbar is complete now:
Let’s look at the content inside the window next. We can keep the basic structure of the listbox from the template, but obviously we want to change what’s in the list.
I’ve prepared some example content we can just copy and paste that into our mockup. Each article consists of three labels, one using the regular font size (10.5pt), and two using the small one (9pt). The metadata label also uses a lighter gray, to distinguish it from the body copy (you can get the color from the labels on the right side of the list in the template using the color picker tool).
The list from the template is grouped and has a clipping mask to cut off scrolling content at the bottom. Since our layout is different anyway we can remove the clipping by simply ungrouping (Ctrl + Shift + G). Next, we can delete all content except the first row, and change that to our first article.
In order to accommodate multiple pieces of content inline as part of the same label, a common pattern is to use middle dots (“·”) as dividers. Pro tip: The Typography app makes it easy to copy and paste typographic symbols like this one into your mockups.
After adding the articles in the first listbox, we need the “Show more” button at the bottom. For that we can just resize the list so it extends past the last article, and add a centered label on that area.
Some of the articles also have images associated with them (there are download URLs for the images in the example content file). Images that aren’t already square need to be clipped to a square shape for our layout. To do that in Inkscape
Pull in the image via drag and drop from the file manager (or paste it directly from a website via “Copy Image”)
Place a rectangle with the right size/proportions where we want the image to go in the layout. In this case, images should be 80px squares, with 12px spacing all around.
Move and scale the image to cover the rectangle on all sides
Select both the image and the rectangle, and do Object > Clip > Set. Note that the clipping object (the rectangle) needs to be above the target (the image).
With the first list done, we can move it down a bit and add a title above it. You can re-use one of the titles from the list for that, and just horizontally align it with the list container. Spacing between title baseline and list should also be 12px, and above the title 18px to the edge of the view.
After that, our first list is complete:
For the second list we can duplicate our first list, move it down below, and just change the content:
In order to have it cut off nicely at the bottom we can bring back a clipping mask. Group the list, duplicate the window background rectangle, and use that as a clipping mask for the list. To make the last article a little more visible I’m also resizing the window background to be a little bit taller first.
For the primary menu we can pretty much just re-use the menu from the template (top left, outside the canvas). Copy over the template popover and button, and vertically align it so the button is at the same height as the one in the window.
Since we don’t need many actions other than the default ones, all we need to do here is change a few labels, add another divider, and put in the name of the app.
That leaves us with a bunch of whitespace in the popover though, so let’s move up the actions and then resize the popover by selecting the bottom nodes and moving them up using the arrow keys:
And with that, our menu looks pretty good:
That completes our desktop view, and we can move on to mobile.
Now that we have a desktop view, let’s do a mobile version of it. Let’s have another look at our sketch:
We can re-use all the elements from the desktop view here, but we need to resize and move around a few things.
As a starting point for the layout, let’s bring in the mobile template. I like to align the mobile headerbar with the desktop one vertically, so all the headerbar buttons have the same vertical position.
Headerbar & Navigation
On mobile sizes there’s not enough horizontal space to keep the view switcher in the headerbar, so instead there’s just a title. The view switcher is in a separate bar at the bottom.
For the headerbar we can duplicate the buttons from the desktop mockup and use them to replace the placeholder buttons on the mobile template.
For the switcher, start by deleting all items except one. Then center the remaining one, and resize the background rectangle to a bit less than a third of the width of the view.
After that you can duplicate the item twice, and move the two additional switcher items to the sides:
Now you can change the icons and strings, and delete the backgrounds on two of the items, and we have a complete mobile switcher:
Adapting the content is easy in this case. Duplicate the lists from the desktop mockup, left-align it with the lists from the template and delete the original lists.
Then we just need to resize the text boxes by moving the handle on the right of the baseline, truncate the text to two lines, move the images to 12px from the right edge, and center the “Show More” label.
Repeat the same thing for the second list, and we have a complete mobile layout!
Page Size & Export
If we zoom out and look at the whole thing together, we can see that this looks pretty much done now:
However, the canvas size is too big for the content we have. Open Document Properties (Ctrl + Shift + D) and change the size to about 1780×1100px.
This is what it looks like with the new page size:
Now that the mockup is ready, let’s export a PNG for easy sharing. Open the Export dialog (Ctrl+Shift+E), choose “Page” at the very top, make sure the DPI is 96, and set the file path. Then press Export, and try opening the PNG in an image viewer to check if there are any issues you missed.
On the design team we usually then push the finished mockup to a git repository, but that’s out of scope for this tutorial.
Congratulation, you made it all the way to the end! I hope this was useful, and you’ll go on to make many great mockups using what you learned :)
You can download the SVG for the mockup I created for this tutorial from GNOME Gitlab. It might come in handy if you have problems with a specific part of the tutorial and want to see how I did it. By the way: The inkscape-tutorial-resources repository contains snapshots of all templates and resources used in this tutorial, in case the original ones change in the future.
Obviously for a real mockup we’d do additional screens (e.g. the article page, various other menus, settings screens, and the like), but I think we’ve covered most of the basics with just this one screen. If you have questions feel free to comment or get in touch!