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!
This is Part 2 of a series on what’s wrong with the free desktop app ecosystem and how we can fix it, based on the talk Jordan Petridis and I gave at LAS 2019 in Barcelona.
In Part 1 we looked at all the different elements making up a platform, and found that there is only one “complete” platform in the free software desktop world at the moment. This is because desktops control the developer platforms, while packaging and system integration is managed by separate communities, the distributions, for historical reasons. This additional layer of middlemen is a key reason why we don’t have real platforms.
Power to the Makers
The problems outlined in Part 1 are of coursenot new, and people havebeen workingon solutions to them for a long time. Some of these solutions have really started to come together over the last few years, empowering the people making the software to distribute it directly to the people using it.
Thanks to the work of many amazing people in our community you can now develop an app in GNOME Builder, submit it to Flathub, get it reviewed, and have it available for people to install right away. Once it’s on there you can also update it on a schedule you control. No more waiting 6 months for the next distribution release!
But though this is all very awesome, Flatpak is unfortunately not a complete solution to the platform conundrum discussed earlier in this series.
Flatpak is Not Enough
Flatpak does solve a number of the issues around app distribution very elegantly, because app developers do their own packaging, and control their release schedule. It’s also a unified package format that works across different host systems, and the Flatpak runtimes are clearly defined development targets to do QA against.
But that doesn’t magically fix all our problems. The two elephants in the room are
The Host still matters: Flatpak only solves part of the issues with distro packaged apps
Downstream drama: Flatpak does not address the conflicts between desktops and distributions
1. The Host Still Matters
Even with Flatpak there are still some unpredictable variables on the host system which affect app developers. On the technical side a number of things can go wrong, from an outdated Flatpak version (which can mean some Portals apps rely on may be missing), to missing/incompatible system APIs such as password storage, calendar, or address book.
These things can lead to applications not working properly, or at all. For example, this is why new versions of GNOME Contacts cannot access any contacts on Debian 10, why recent GNOME Calendar cannot access any calendars on Ubuntu 18.04, or why Fractal doesn’t remember your password across restarts on some non-GNOME environments.
There are also user-facing integration points where applications interface with the system. These include things like notifications, the application menu, search providers, the old systray, and the design patterns used in individual apps.
For example, when the system UI or design guidelines change, applications follow the platform and change their UI accordingly. This means if you install newer apps on an older system, there are going to be weird edge cases. For example, if you install new apps on Debian 10 you get a confusing mix of the old and new application menu paradigms because the design guidelines were changed with GNOME 3.32 (early 2019).
Flatpak also applies the host GTK stylesheet and icon set to apps. This means that if the host distribution overrides the system stylesheet, Flatpak will happily apply random, never-tested CSS to every app. Obviously this leads to lots of issues, ranging from ugly but relatively harmless glitches to real usability issues, such as illegible text on buttons. For more background on this particular issue, see this blog post.
Some of these issues could be fixed with more standardization, changes to Flatpak, or new portals. However, fundamentally, in order to be a real platform you need a clearly defined environment to develop and test for. Flatpak alone is not enough to achieve that.
Just like “write once, run everywhere” is always an illusion, it’s never going to be possible to completely split apps from the OS. You always need app developers to do some extra work to support different environments, and currently every distribution represents yet another extra environment to support.
2. Downstream Drama
Flatpak does not completely solve the issues app developers face in shipping their software, because these can not be isolated from the ones desktop developers face. In order to fix the app developer story we need real platforms. In order to get those we need to resolve the desktop/distribution dilemma.
The issues here roughly match the ones with traditional distribution packaging mentioned in Part 1, and can be grouped into three broad categories:
Structural issues inherent to having distributions and desktops be separate projects.
Fragmentation issues because we have multiple of everything so there’s duplication and/or bad abstraction layers.
Configuration issues, primarily around settings and other defaults, which have to be set at the distribution level but affect the user experience.
One of the biggest structural issues is distribution release schedules not being aligned with the upstream one (or between different distributions). GNOME releases every 6 months, but distributions can take anywhere from a few weeks to several years to ship these releases.
This category also includes distributions overriding upstream decisions around system UX, as well as theming/branding issues, due to problematic downstream incentives. This means there is no clear platform visual identity developers can target.
For example, Ubuntu 18.04 (the current LTS) ships with GNOME 3.28 (from March 2018), includes significant changes to system UX and APIs (e.g. Unity-style dock, desktop icons, systray extension), and ships a branded stylesheet that breaks even in core applications.
Having multiple implementations of everything means we either need do tons of duplicate work, or try to abstract over the different implementations.
On one end of the spectrum there are OS installers: There is no GNOME installer, so every distribution builds their own. Unfortunately, most of these installers are not very good, and don’t integrate well with the rest of the desktop experience (e.g. they use different design patterns than the OS itself). This can be either due to a lack of resources (e.g. not every downstream has their own GNOME designers), or because different distributions have specific downstream goals and motivations (e.g. Fedora and RHEL share an installer, which introduces lots of complexity).
In other areas we have the opposite problem, because we’re trying to abstract over the fragmentation with a single component. For example, PackageKit is meant to abstract over different package formats, but in practice it only works for a handful of them, and even for those it’s often buggy. The PackageKit maintainers have officially given up on this approach.
This includes the default apps, the fonts shipped with the system by default, the terminal shell and prompt, and the UX around things like Plymouth. All of these things are usually configured at the distribution level and are therefore often not great, because these choices need to be made in concert with the rest of the platform UX.
Given the constraint of there being multiple different desktops projects and technology stacks (and the host still mattering), we’ll never have a single “Linux” or “FreeDesktop” platform. We could have one platform per desktop though.
From an app developer point of view, testing for GNOME, KDE, and elementary isn’t as nice as testing only for a single platform, but it’s not impossible. However, testing for Debian, Fedora, multiple Ubuntu releases, OpenSUSE, Arch, Endless, and dozens more is not and never will be feasible, even with Flatpak. Multiple different distributions, even ones that ship the same desktop environment, don’t add up to a platform. But exactly that is what we need, one way or another.
The question is, how do we get there?
The Nuclear Option
When we look at it from a Flatpak context, the solution seems obvious. Flatpak is solving the middleman problem for app developers by circumventing the distributions and providing a direct channel between developers and end users. What if we could do the same thing for the OS itself?
Of course the situation isn’t exactly the same, so what would that mean in practice?
With Flatpak runtimes there is no extra “distribution” abstraction layer. There are no Debian or Fedora runtimes, just GNOME and KDE, because those are the technology stacks app developers target.
These runtimes are already more or less full-fledged distributions which are controlled by the desktops, we’re just not using them as such. The Freedesktop SDK (which most runtimes are based on) is not based in any distro, but built directly from upstream sources using Buildstream as the build tool, and it already has most of the things you need to make a basic operating system.
There is an early-stage effort to make bootable nightly GNOME OS images for development/testing, built on top of the Freedesktop SDK. From there it wouldn’t be a huge leap to actually make an independent, consumer-facing platform OS for GNOME (and KDE, and other platforms).
However, though this is likely to become a very attractive solution in the future, there are a number of hurdles to be overcome:
An OS needs an installer, OS updates, a Plymouth theme, etc. All of these are being worked on for the nightly GNOME OS images, but are not quite there yet.
A “real” OS needs a dedicated group of people doing things like release management, security tracking, and QA. These are being done to some degree for the Flatpak runtimes, but a consumer OS would need more manpower.
It’s an OSTree-based immutable system, which means there is no traditional package management. Apps are installed via Flatpak, and server/developer workflows need to happen in containers. Though projects like Silverblue’s toolbox have come a long way over the past few years, there’s still work to be done before immutable OSes can painlessly replace systems with old-school package managers for all use cases.
It takes time to start a new operating system from scratch, especially when it’s using cutting-edge technology. So while things like GNOME OS could be amazing in the longer-term future, it’s likely going to take a few more years before this becomes a viable alternative.
Squaring the Circle
What could we do within the constraints of the technology, ecosystem, and communities we have today, then? If we can’t go around distributions with a platform OS, the only alternative is to meld the distributions into a meta platform OS.
Technically there’s nothing stopping a group of separate distributions from acting more or less like a unified platform OS together. It would require extraordinary discipline and compromise on all sides (admittedly not things our communities are usually known for), but given how important it is that we fix this problem, it’s at least worth thinking about.
To get an idea what this could look like in practice, let’s think through some of the specific issues mentioned earlier:
Release Schedule: This is probably among the thorniest issues since release cycles vary wildly in length and structure, and changing them is very difficult. It’s not unimaginable that at least some progress could be made here though. For example, GNOME could have long term support releases every 2-3 years for “stable” distributions like RHEL and Ubuntu LTS. Distributions could then agree to either be on the regular 6 month schedule, or the 2 year “LTS” schedule. Alternatively, all distributions could find a single compromise schedule that can work for everyone (e.g. maybe one release per year, like mobile operating systems do).
Theming/Branding: Some distributions want ways to customize the OS experience such that their system looks recognizably different from others. This is not necessarily a problem, as long as this is done using APIs that are supported and intended to be used in this way (which unfortunately is currently not happening in many cases).
Creating more branding opportunities which do not break APIs which apps rely upon (especially third party apps shipped via Flatpak), is certainly possible and there have been discussions in this direction (e.g. GTK accent colors). Whether distributions would limit themselves to these APIs once they exist is of course an open question, but at least there is a ongoing dialog about this.
System UX/API Changes: Some distributions make significant changes to the core system, which fragments the visual identity of the platform at best, and severely damages the app ecosystem at worst. This includes things like adding a permanent dock, icons on the desktop, re-enabling the systray, or a “dark mode” setting which just changes the system stylesheet from under apps.
The solution here is simple in theory: If you think a change to the system UX is needed to fix a specific problem, don’t just patch it downstream, but instead help to address the actual underlying issue (We already touched on this in Part 1). For example, if you find that new users are confused by the empty desktop at startup, don’t just ship an extension that completely breaks the structure of the shell. Bring the problem to the upstream designers and developers, figure out a solution together, and help implement it upstream.
In practice it’s not always that easy, but a lot can be done by simply adopting an upstream-first UX mindset. It can take a while to get used to, especially for companies with more, uh, “traditional” internal processes, but it’s definitely possible seeing as it’s working well for Red Hat and Purism, for example.
OS Installer: It may not be doable to have a single code base, but we could definitely share at least the design (and possibly some UI code) for the installers used across distributions. A cross-distribution initiative for nice, native GNOME installers across the major distributions would probably not be easy logistically, but is not unimaginable.
Software Installation & Updates: GNOME Software and PackageKit’s “abstract across distros” strategy has clearly failed, and we need a new approach here. For applications there is a relatively easy solution: Distributions stop packaging apps, and work together on a common repository of developer-submitted Flatpaks (e.g. something like Flathub). We’d need to work out how this common solution can accommodate various distribution policies around e.g. proprietary software, but this seems very doable and most of it already exists in Flathub.
The resources currently going into repackaging every app for every distribution could be pooled to review the apps submitted by developers to the common Flatpak repository.
Seeing as most distributions are not (yet) image-based like e.g. Silverblue or Endless, we would still also need a way to update the packages that make up the core system. For this there’s probably no way around backend duplication.
System Default Configuration: Making progress in this area is likely not too difficult comparatively. The main thing we’d need is better coordination between the various parties needed to synchronize these things better (which is of course easier said than done). Having some kind of common forum where the upstream design and release team, as well as people in charge of major distributions can discuss and standardize defaults across the entire ecosystem might work for that.
The Bottom Line
If we want a future with real platforms we can either go around the distributions or have them all work together (or potentially both), but one way or another we need to vertically integrate.
Neither path is straightforward or easy, and there’s a huge amount of work ahead either way. However, the first and most important step is acknowledging that this problem exists, and that we need to radically change our approach if we’re serious about building attractive app ecosystems.
The good news is that many people across different projects are already working towards enabling this future. We hope that you’ll join us.
There was a point in my life when I ran Arch, had an elaborate personalized terminal prompt, and my own custom icon theme. I stopped doing all these things at various points for different reasons, but underlying them all is a general feeling that it’s taken me some time to figure out how to articulate: I no longer want to invest time in things that don’t scale.
What I mean by that in particular is things that
Only fix a problem for myself (and maybe a small group of others)
Have to be maintained in perpetuity (by me)
Not only is it highly wasteful for me to come up with a custom solution to every problem, but in most cases those solutions would be worse than ones developed in collaboration with others. It also means nobody will help maintain these solutions in the long run, so I’ll be stuck with extra work, forever.
Conversely, things that scale
Fix the problem in way that will just work™ for most people, most of the time
Are developed, used, and maintained by a wider community
A few examples:
I used to have an Arch GNU/Linux setup with tons of tweaks and customizations. These days I just run vanilla Fedora. It’s not perfect, but for actually getting things done it’s way better than what I had before. I’m also much happier knowing that if something goes seriously wrong I can reinstall and get to a usable system in half an hour, as opposed to several hours of tedious work for setting up Arch. Plus, this is a setup I can install for friends and relatives, because it does a decent job at getting people to update when I’m not around.
Until relatively recently I always set a custom monospace font in my editor and terminal when setting up a new machine. At some point I realized that I wouldn’t have to do that if the default was nicer, so I just opened an issue. A discussion ensued, a better default was agreed upon, and voilà — my problem was solved. One less thing to do after every install. And of course, everyone else now gets a nicer default font too!
I also used to use ZSH with a configuration framework and various plugins to get autocompletion, git status, a fancy prompt etc. A few years ago I switched to fish. It gives me most of what I used to get from my custom ZSH thing, but it does so out of the box, no configuration needed. Of course ideally we’d have all of these things in the default shell so everyone gets these features for free, but that’s hard to do unfortunately (if you’re interested in making it happen I’d love to talk!).
Years ago I used to maintain my own extension set to the Faenza icon theme, because Faenza didn’t cover every app I was using. Eventually I realized that trying to draw a consistent icon for every single third party app was impossible. The more icons I added, the more those few apps that didn’t have custom icons stuck out. Nowadays when I see an app with a poor icon I file an issue askingifthedeveloperwouldlikehelp with a nicer one. This has worked out great in most cases, and now I probably have more consistent app icons on my system than back when I used a custom theme. And of course, everyone gets to enjoy the nicer icons, not only me.
Some other things that don’t scale (in no particular order):
Separate home partition
Non-trivial downstream patches
Multiple Firefox profiles
User styles on websites
Running your blog on a static site generator
Hosting your own email (and self-hosting more generally)
Google-free Android (I use Lineage on a Pixel 1, it’s a miserable existence)
Buying a Windows computer and installing GNU/Linux
Custom keyboard shortcuts, e.g. for launching apps (I still have a few of these, mostly because of muscle memory)
The free software community tends to celebrate custom, hacky solutions to problems as something positive (“It’s so flexible!”), even when these hacks are only necessary because things are broken by default. It’s nice that people with a lot of time and technical skills can fix their own problems, but the benefits from that don’t automatically trickle down to everybody else.
If we want ethical technology to become accessible to more people, we need to invest our (very limited) time and energy in solutions that scale. This means good defaults instead of endless customization, apps instead of scripts, “it just works” instead of “read the fucking manual”. The extra effort to make proper solutions that work for everyone, rather than hacks just for ourselves can seem daunting, but is always worth it in the long run. Just as with accessibility and commenting your code, the person most likely to benefit from it is you, in the future.
After the name, the app icon is the most important part of an app’s brand. The icon can help explain at a glance what the app does, and serves as an entry point to the rest of the experience. A high quality icon can make people want to use an app more, because it’s a stand-in for the quality of the entire app.
Think of the app icon like an album cover for your app. Yes, technically the music is the same even if you have a terrible cover, but a great cover can capture the spirit of the album and elevate the quality of the thing as a whole.
The first thing you need is a metaphor, i.e. some kind of physical object, symbol, or other visual artifact that symbolizes your application.
Finding a good metaphor is a fuzzy and sometimes difficult process, as it’s often hard to find a physical object many people will recognize as related to the domain of your app. There are no hard and fast rules for this, but ideally your icon metaphor should fall into one of these categories:
Physical objects directly related to what the app does (e.g. a speaker for Music)
Physical objects vaguely related to the app’s domain or an older analog version of it (e.g. a cassette tape for Podcasts)
Symbols related to the domain (e.g. the “play” triangle for Videos)
A simplified/stylized version of the app’s user interface (e.g. Peek)
There are also anti-patterns for metaphors which should be avoided, if possible:
My process for brainstorming metaphors is quite similar to the one I use to brainstorm names: I come up with a few ideas for physical objects, put them in a thesaurus to find more related ones, and repeat that until I have a list with at least a few viable candidates.
Let’s start with related physical objects:
How about related non-objects? Maybe we can find some more interesting objects that way:
Reading, the activity: Couch, reading light, tea/coffee, glasses
Later (as in, “read later”): Clock, timer
Collecting things: Folder, clipboard
Now that we have a few options, let’s see which ones are viable. Ideally, the metaphor you choose should have these attributes:
Somewhat specific to the app’s domain (e.g. a book is probably too generic in our case)
Recognizable at small sizes
Can be drawn in a simple, geometric style (this can save you a lot of work later on)
In this case, the most viable options are probably
Stack of books
One of the above + a clock
Now that we have some metaphors, let’s try to sketch them to see if they make for good icons. I usually use pencil and paper for this, but you can also use a whiteboard, digital drawing tablet, or whatever else works for you to quickly visualize some concepts.
While sketching it’s good to think about the overall shape your icon will have. If it makes sense for your metaphor, try to make the icon not just a simple square or circle, but something more unique and interesting. If it doesn’t make sense in your case don’t force it though, there are other ways to make the icon visually unique and interesting, such as color and structure.
In this case, it looks like there are a number of viable concepts among our sketches, though nothing jumps out as the obvious best option. I kind of like the bookshelf, so let’s try going forward with that one.
Start from a Template
We now have a concept we like, so we can move to vector. This is where we can start using the shiny new icon design tools!
Open App Icon Preview, and hit the “New App Icon” button on the welcome screen. We’re asked for the Reverse Domain Name Notation name of the app (e.g. org.mozilla.Firefox), and where to store the icon project file.
In most cases you’ll want to keep this file in your app’s git repository. Think of it as your icon’s source file, which the final icon assets are later exported from.
After that, the icon will open in preview mode in App Icon Preview. Now we open the same file in a vector drawing app, and edit it from there. Every time we save the source file, the preview will automatically update.
Now we have our icon source file open in both App Icon Preview and Inkscape. Icon Preview shows just the icon grid:
In Inkscape, open the Layers panel (Ctrl + Shift + L) and check out the layer structure. The icons layer is where the actual icon goes. The grid and baseplate layers contain the icon grid and the canvas respectively.
Behind everything else is the template layer, which doesn’t contain anything visible and is only needed so App Icon Preview can get the canvas size for preview and export. Don’t change, hide, rename, or delete this layer, because the icon might not show up in App Icon Preview anymore.
When previewing the icon in App Icon Preview you’ll want to hide the grid and baseplate layers (using the little eye icon next to the layers).
Make sure you have the GNOME HIG Colors palette in Inkscape. Inkscape 1.0 Beta has it by default, otherwise you can download it from the HIG App Icons repository and put it in ~/.var/app/org.inkscape.Inkscape/config/inkscape/palettes for Flatpak Inkscape or ~/.config/inkscape/palettes if it’s on the host. There’s also a color palette app, which you can get on Flathub.
Once you’re familiar with the template, you can start drawing your icon idea as vector. If you’re using Inkscape and aren’t very familiar with the app yet, here’s a quick overview of the things you’ll likely need.
Toolbox (the toolbar on the left edge)
Selection/movement/scaling tool (S)
Rectangle tool (R)
Ellipse tool (E)
And if you’re doing something a little more advanced:
Bezier path drawing tool (B)
Path & node editor (N)
Dialogs Sidebar (configuration dialogs docked to the right side)
Fill & Stroke (Ctrl + Shift + F)
Align & Distribute (Ctrl + Shift + A)
Layers (Ctrl + Shift + L)
Snap Controls (the toolbar on the right edge) Inkscape has very fine-grained snapping controls, where you can 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 :)
Of course, teaching Inkscape is a bit out of scope for this guide. If you’re just getting started with it, I recommend doing a few beginner tutorials first to familiarize yourself with the basic workflows (especially around the tools listed here).
The GNOME Icon Style
Traditionally, GNOME app icons were very complex, with lots of photorealistic detail and many different sizes which had to be drawn separately. This changed when we revamped the style in 2018, with the explicit goal of making it easier to produce, and more approachable for third party icon designers.
The new style is very geometric, so in many cases you can draw an entire icon with just basic shapes.
One important attribute of the style is the abstract perspective. Even though the style is simple and geometric, it’s not “flat”: It makes use of material, depth, and perspective, but in a way that is optimized for easy production as vector.
The perspective works by “folding” horizontal and vertical layers into one dimension, so you can see the object orthogonally from both the top and the front.
This results in a kind of “chin” an the bottom of the object, which is shaded darker than the top surface, since light comes evenly from the top/back.
In practice, this usually doesn’t have a huge impact, since it’s also suggested to make objects not too tall, when possible. A lot of icons are just a simple 2D shape with a small chin at the bottom.
That said, it can look very weird when you get the perspective wrong, e.g. by folding the layers from the top/back instead of the front, so it’s important to keep this in mind.
Material & Lighting
Icons can make use of skeuomorphic materials (e.g. wood, metal, or glass) if it’s needed for the physical metaphor, but outside of those special cases it’s recommended to keep things simple.
Straight surfaces have flat colors (instead of e.g. slight vertical gradients), but curved surfaces can/should have gradients. The corners on the chin on rounded base shapes should have a highlight gradient.
Shadows inside the icon should be avoided if possible, but can be used if necessary (e.g. for contrast reasons). Do not use drop shadows that affect the app outline though, because GTK renders such a shadow automatically.
Icon Grid & Standard Shapes
In order to make sure icons are somewhat similar in size, alignment, etc. we have a grid system.
The canvas is 128x128px (for legacy reasons), but you’re designing for 64×64, while also taking 32×32 into account where possible. In general, it’s good to make sure you’re putting as many lines as possible on grid lines, so they’re sharp even at 32. Testing in App Icon Preview helps a lot with this.
The icon grid also has some standard shapes for wide, tall, square, and circular icons, which can be used as a basis for the structure of the icon if it makes sense for the metaphor (e.g. if the object is more or less square, use the square standard shape).
Protip: Great Artists Steal Reuse
There are lots of apps with icons in the GNOME style out there, and they’re all free software. If there’s something you like about another app’s icon you can get the source from GNOME Gitlab or Github, look at how a certain object is drawn, or just take (parts of) other icons and adapt them to your needs.
This is especially useful for common objects needed in many icons, e.g. pencils, books, or screens. The icon template in App Icon Preview comes with a few of these common objects on the canvas, which can be a good starting point for new icons.
Draw, Preview, Repeat!
Armed with this knowledge about the style and tooling, we can finally jump in and start drawing! In this case I re-did the sketch at a slightly larger size to get a better feel for it:
Now let’s try vectorizing it. Since the overall shape is a tall rectangle, we can start with the tall rectangle standard shape. If we change the color to brown, and make the chin at the bottom thicker (by resizing the top layer vertically), we have the basic frame for the shelf.
After that we can add the actual shelves, by simply adding two slightly darker brown rectangles (the back of the shelf), and two wide rectangles at the top of these (the bottom of the horizontal shelf).
Changing the color of the chin is a bit tricky, because it has a horizontal gradient. It requires selecting the bottom rectangle with the gradient tool, clicking each gradient stop manually and changing it to brown by clicking one of the colors in the color palette at the bottom edge of the window.
Let’s see what this looks like in Icon Preview now:
Getting there, right? Now let’s add some books. Lucky for us, book spines can also be drawn as rectangles, so this shouldn’t be too hard. We don’t want too much detail, because we’re designing for 64px first and foremost. Something like 10 books per row should work.
If we want to get fancy we can also round the top of the spine on some of the books by adding an ellipse of the same color, but it’s not really needed at this size.
Looking good! I think we’re done with the full-color icon.
If at this point in the process you feel like the concept or metaphor isn’t working out (for example because it doesn’t look interesting enough, or because it’s too complicated to work at small sizes) you can always go back a few steps and try vectorizing a different one of your sketches. The nice thing about the simplicity of this style is that you can do this without losing weeks of work, making iteration on concepts much more feasible.
Now that the full-color icon is done, we can start thinking about the symbolic icon for our app. Ideally this is a simplified, one-color version of the app icon, designed for a 16×16 px canvas. It’s used in notifications and some other places in the Shell where a colorful icon would not be appropriate.
I won’t go into too much detail on this here since drawing good symbolics is a big topic, and this post is too long already. I might expand on this in a future post, but for now here are a few quick tips:
Alignment to the pixel grid is very important here if you don’t want the icon to end up a blurry mess
Stick to the original metaphor if at all possible, go for something else if not
Test in App Icon Preview to make sure the icon is actually recognizable at 16px
If possible leave the outermost 1px empty on all sides
Most strokes should be 2px, but they can be 1px in some cases
Don’t overthink it for the first version. This icon is a secondary thing, and it’s relatively little effort to fix/redo it later :)
Our bookshelf example looks tricky at first glance, because we have all these tiny books, and only 16 pixels to work with. However, if we simplify it enough it’s not too hard to get something decent. We can just use a two tall and two wide rectangles to draw the shelf, and three smaller rectangles as books on each shelf:
And that’s it! We have a real app icon now, with everything that entails. If you want to have a look at the source for the icon we made in this tutorial, you can download the SVG here. It includes the final icon and some of the intermediate steps.
Now that we’re happy with the icon, we can press the “Export” button in App Icon Preview and save the final icon assets. The app will automatically optimize the SVGs for size, and if you have nightly builds of your app, you also get an automatically generated nightly icon without any extra work!
Congratulations for making it all the way to the end! I hope you found this tutorial useful, and will go on to make great icons for your apps. If there’s anything you found unclear while following along, please let me know in the comments.
In our community there is this idea that “Linux” is the third platform next to Windows and macOS. It’s closely connected to things like the “year of the Linux desktop”, and can be seen in the language around things like Flatpak, which bills itself as “The Future of Apps on Linux” and the Linux App Summit, which is “designed to accelerate the growth of the Linux application ecosystem”.
But what does that actually mean? What does a healthy app ecosystem look like? And why don’t we have one?
I think the core of the problem is actually the layer below that: Before we can have healthy ecosystems, we need healthy platforms to build them on.
What is a Platform?
The word “platform” is often used without a clear definition of what exactly that entails. If we look at other successful platforms there are a ton of different things enabling their success, which are easy to miss when you just look at the surface.
On the developer side you need an operating system developers can use to make apps. You also need a developer SDK and tooling which are integrated with the operating system. You need developer documentation, tutorials, etc. so people can learn how to develop for the platform. And of course once the apps are built there needs to be an app store to submit them to.
Developers can’t make great apps all by themselves, for that you also need designers. Designers need tools to mock up and prototype apps, platform UI patterns for things like layout and navigation, so every app doesn’t have to reinvent the wheel, and a visual design language so designers can make their app fit in with the rest of the system visually. You also need Human Interface Guidelines documenting all of the above, as well as tutorials and other educational resources to help people learn to design for the platform.
On the end user side you need a consumer OS with an integrated app store, where people can get the great apps developers make. The consumer OS can be the same as the developer OS, but doesn’t have to be (e.g. it isn’t for Android or iOS). You also need a way for people to get help/support when they have problems with their system (whether that’s physical stores, a help website, or just easily google-able Stackoverflow questions).
That’s a lot of different things, but we can group them into four major pieces which are needed in order for something to be a real platform:
So if we look at the free software world, where are the platforms?
Linux is a kernel, which can be used to build OSes, which can be used to build platforms. Some people (e.g. Google with Android) have done so, but a kernel by itself doesn’t have any of the four things outlined above, and therefore is not a platform.
What about “Desktop Linux”, which is what people usually mean when they say “Linux”? The problem is that this term doesn’t have a clear definition. You could take it to mean “FreeDesktop.org”, but that also doesn’t come close to being a platform. FreeDesktop is a set of standards that can be used to build platforms (and/or ensure some level of compatibility between different platforms). Endorsement of a single platform or set of technologies goes directly against FreeDesktop’s aims, and as such it should only be thought of as the common building blocks platforms might share.
What about distributions? Ubuntu is one of the most popular ones, and unlike others it has its own app store. It still isn’t a platform though, because it doesn’t have the most critical pieces: a developer SDK/technology stack, and a design language.
Other distributions are in a similar but worse position because they don’t have an app store.
GNOME is the most popular desktop stack, and it does have an SDK and design language. However, it only sort of has an app store (because GNOME people work on Flathub), and it doesn’t have an OS. Many distributions ship GNOME, but they are all different in various ways (more on this later), so they don’t provide a unified development target.
Interestingly, the only project which currently has all the pieces is elementary. It has an OS, an SDK, a HIG, and an app store to submit apps to. The OS is largely Ubuntu and the technology stack largely GNOME, but it develops its own desktop and apps on top of that, and does the integration work to make it into a complete consumer product.
This begs the question, why is elementary the only one?
The Means of Distribution
The reasons for this are largely historical. In the early days, free software desktops were a bunch of independently developed components. They were not necessarily designed for each other, or well integrated. This meant in order to have a usable system, someone needed to curate these components and assemble them into an operating system: The first distributions were born.
Over the last decades this landscape has changed drastically, however. While GNOME 1 was a set of loosely coupled components, GNOME 2 was already much more cohesive and GNOME 3 is now essentially an integrated product. The shell, core apps, and underlying technologies are all designed with each other in mind, and provide a complete OS experience.
Desktops like GNOME have expanded their scope to cover most of the responsibilities of platforms, and are in effect platforms now, minus the OS part. They have a very clear vision of how the system should work, and app developers target them directly.
The elementary project has taken this development to its logical end point, and made its own vertically integrated OS and app store. This is why it’s the only “real” platform in the free software space at the moment.
Distributions, on the other hand, have not really changed since the 90s. They still do integration work on desktop components, package system and applications, set defaults, and make UX decisions. They still operate as if they’re making a product from independent components, even though the actual product work is happening at the desktop layer now.
This disconnect has led to tensions in many areas, which affect both the quality of the system user experience, and the health of the app ecosystem.
What’s interesting about this situation is that desktop developers are now in the same situation app developers have always been in. Unlike desktops, apps have always been complete products. Because of this they have always suffered from the fragmentation and disconnect between developers and users introduced by distribution packaging.
Grievances with the distribution model, which affect both app and desktop developers, include:
Release schedule: Developers don’t have control over the pace at which people get updates to their software. For apps this can mean people still get old versions of software with issues that were fixed upstream years ago. For desktops it’s even worse, because it means app developers don’t know what version of the platform to target, especially since this can vary wildly (some distributions release every 6 months, others every 2+ years).
Packaging errors: Distribution packaging is prone to errors because individual packagers are overloaded (often maintaining dozens or hundreds of packages), and don’t know the software as well as the developers.
Overriding upstream decisions: When distributions disagree with upstream decisions, they sometimes keep old version of software, or apply downstream patches that override the author’s intentions. This is very frustrating if you’re an app developer, because users never experience your app as you intended it to be. However, similar to the release schedule issue, it’s even worse when it happens to the core system, because it fragments the platform for app developers.
Distro Theming: App developers test with the platform stylesheet and icons, so when distributions change these it can break applications in highly visible ways (invisible widgets, unreadable text, wrong icon metaphors). This is especially bad for third party apps, which get little or no testing from the downstream stylesheet developers. This blog post explains the issue in more detail.
The Wrong Incentives
The reason for a lot of these issues is the incentives on the distribution side. Distributions are shipping software directly to end users, so it’s very tempting to solve any issues they find downstream and just ship them directly. But because the distributions don’t actually develop the software this leads to a number of other problems:
Perpetual rebasing: Any change that isn’t upstreamed needs to be rebased on every future version of the upstream software.
Incoherent user experience: Downstream solutions to UX problems are often simplistic and don’t fix the entire issue, because they don’t have the development resources for a proper fix. This leads to awkward half-redesigns, which aren’t as polished or thought-through as the original design.
Ecosystem fragmentation: Every downstream change adds yet another variable app developers need to test for. The more distributions do it, the worse it gets.
The Endless OS shell is a great example of this. They started out with vanilla GNOME Shell, but then added ever more downstream patches in order to address issues found in in-house usability tests. This means that they end up having to do huge rebasesevery release, which is a lot of work. At the same time, the issues that prompted the changes do not get fixed upstream (Endless have recently changed their strategy and are working upstream much more now, so hopefully this will get better in the future).
This situation is clearly bad for everyone involved: Distributions spend a ton of resources rebasing their patches forever, app developers don’t have a clear target, and end users get a sub-par experience.
So, what could we do to improve this? We’ll discuss that in part 2 of this series :)
This October I attended the GNOME Shell Hackfest 2019 in the Netherlands. It was originally just planned as a small hackfest for core Shell developers, but then us designers decided to crash the party and it became a pretty big thing. In the end we were about 15 people from lots of different companies, including Red Hat, Endless, Purism, and Canonical. The venue was the Revspace hackerspace in Leidschendam, which is somewhere between the Hague and Leiden.
The venue was very cool, with plenty of hackerspace-y gadgets and a room with couches and a whiteboard, which was perfect for the design team’s planning sessions.
Allan, Jakub, and I were primarily there to make progress on some long-standing issues with GNOME Shell, such as new user onboarding, the app grid, and the spatial model of the Shell. We’ve wanted to address many of these things for a long time (in fact, some of them were already discussed at the London hackfest 2 years ago). In the weeks leading up to the hackfest we had already been working on this (together with Sam Hewitt who couldn’t make it to the hackfest unfortunately), preparing a number of concepts to be worked out in more detail.
At the hackfest we made these concepts more concrete, worked on mockups and prototypes, and discussed them with Shell developers. It’s still early days for all of this, but we’re very excited about sharing it more widely soon.
We also worked on a number of other things, such as the new lock screen design, which Georges has started to implement, prettier Shell dialogs, and some changes to the system status menu.
Thanks to Carlos Garnacho and Hans de Goede for organizing, Revspace for hosting us, and the GNOME Foundation for sponsoring my travel and accommodation!
A few weeks ago I attended the Linux App Summit in Barcelona. I arrived very late on Monday night by bus, after almost not making it to Spain that day (my train from Paris stopped in Montpellier due to the rails being destroyed by a storm and the highway was blocked by a protest). Adrien, Julian and I had a shared accommodation, which conveniently was just down the street from the venue.
On Tuesday and Wednesday I attended some talks, but was mostly focused on preparing the talk Jordan and I had on Wednesday afternoon. Talks with multiple presenters are always tough, especially if there’s not much time for practicing, but I think it went okay given the circumstances. There’s a recording on Youtube in the day 2 live stream video.
Over the course of the conference I had lots of good conversations about the state of free software with people from GNOME and other projects. In some areas it’s exciting how far we’ve come (e.g. Flatpak), but in others it’s frustrating how little has changed over the past decades (e.g. fragmentation).
Adrien gave a talk about how GNOME Mobile slowly materialized over the past two years, especially on the application and toolkit side. I was also happy to see not one but two talks (by Florian and Daniel) about how very very dead the Systray is, without anyone really disagreeing. It’s nice to see most people maybe finally on the same page on this. Now we just need Ubuntu to stop shipping a certain extension… ;)
Later in the week I also managed to do a bit of hacking. Now that the GNOME OS images can get updates the main missing piece is an installer, so we discussed that with Javier and Valentin from Codethink. I was also very happy to meet Manuel (the maintainer of UberWriter) in person, and talk about some cool future stuff for that app.
Overall the conference was great! Because there were so many GNOME friends it almost felt like a second GUADEC, but I also met many cool new people. Thanks to the organizers for putting together a great event, to Purism for paying for our accommodation, and the GNOME Foundation for covering my travel.
On Sunday I gave a talk about adaptive patterns and making GNOME apps that work well across form factors, from phones all the way to desktops. There is a video of my talk, and the slides are here.
I spent most of Monday in the GTK BoF, where we discussed (among other things) menus, dark styles, upstreaming Libhandy widgets, and a new pattern library for GNOME. Since there were so many app maintainers in the room, we inevitably also talked about random things in various apps, such as the Mouse/Touchpad settings, the Display settings, and Evince.
One of the things we’ve talked a lot about recently on the GNOME design team is making it easier to implement our UI patterns.
Many of the platform widgets are in GTK directly, which makes them easy to use, but hard to iterate on since we don’t want to break API there. Other things are in third party libraries, such as Libzazzle or Libhandy, but those are not “official”, and app developers have to know about them. Other widgets are just copy-pasted between apps, or completely custom everywhere. This makes it needlessly complex to follow our design guidelines, and has resulted in inconsistency in how different apps implement patterns. One idea to fix this was to have a separate official pattern library, and a new widget factory that showcases these patterns. This library could move significantly faster than GTK, and its release cycle could be better aligned with GNOME.
On a parallel track we’ve also been discussing for some time (both within Purism and GNOME) how best to upstream the widgets in Libhandy. Some of the things in there are fairly generic and should go into GTK (e.g. HdyColumn), but since GTK3 is stable we can’t upstream them directly before GTK4. Other widgets are more GNOME-specific (e.g. HdyPreferencesWindow), and would ideally be able to move at a faster speed, so a separate library would be a better fit.
We discussed this at length over the course of GUADEC, and this seems like the most likely way forward: For GTK4 we’ll have a separate GNOME pattern library outside GTK, which contains “official” widgets implementing patterns from the GNOME HIG. Some of these widgets would come from currently separate libraries such as Libhandy, while others might be moved out of GTK (e.g. GtkShortcutsWindow). The new library would have a clearly defined inclusion/review process for new widgets, and would be kept in sync with the HIG.
For GTK3 it seems like the path of least resistance is to just adopt Libhandy upstream, after removing a few things that are too specific or no longer needed (e.g. HdyDialer and HdyArrows), and instituting the same review process for new widgets as for the GTK4 library.
It’s still early days for all of this, but this is the current consensus as I understood it from various conversations at GUADEC.
Tuesday: Vendor Themes
On Tuesday we had a BoF with various interested parties (including design team, distros, and app developers) to discuss a possible future Vendor Styles API.
GNOME does not currently support making changes to the platform stylesheet/icons, and app developers build their apps with this in mind. Changing these means ripping out API from under developers, which often results in apps looking broken. Some downstreams are doing it however, which is a problem for our overall platform developer story.
The good news is that some of these downstreams realize this is an issue, and are willing to work upstream to improve the situation. During the BoF we discussed the motivations for changing the platform style, and the kinds of changes they’re interested in. We broadly categorized these changes in 3 groups:
“Accent Colors”: Making it possible to change some UI colors (at both the system and app level) without breaking things
“Upstreamable”: Stylistic changes which upstream might be interested in (such as rounded menus, flatter checkboxes, etc.)
“Here Be Dragons”: Anything that touches widget sizing, margins, and the like (because changes to these break apps the hardest)
We spent most of the BoF discussing the “Accent Colors” category, because that’s where most of the low-hanging fruit is. The main things we need to figure out for this are
Which and how many variables do we want (and can realistically be supported)?
How would app developers test for different color combinations? What kind of tooling do we need to make that easier?
How do we ensure good contrast?
Can colors be set arbitrarily or are there constraints?
How are the colors set? What should that API look like?
Could we do this for GTK3 given that it’s stable? Would it be GTK4 only?
How would we handle Appstream screenshots looking different from the app once installed?
We discussed most of these questions in some detail, but all of this needs a lot more work before we can definitively say if and how we’ll go forward with it. At the BoF we outlined some first steps in this direction, namely documenting the current set of color variables within Adwaita, and looking at what other variables we might need. For more on this read the Discourse topic.
Once all of that is figured out though, there are some pretty exciting things on the horizon. For example, some third party app developers would like to use color in more interesting ways in their apps, but the way Adwaita is set up, this is currently not easy. If done right, making Adwaita more flexible would not only allow for vendor styles, but also empower app developers to do more cool stuff.
Another potential benefit is that a lot of the work around ensuring contrast on different background colors, better documentation around color variables, etc. would be needed anyway if we get a global “prefer dark” preference. If and when that happens, it will be a much easier transition if we’ve already worked out some of these things.
Software Freedom/Ethics Ratings
I also sat down with François on Tuesday to discuss the software ethics rating system we’ve been thinking about for a while. The goal of this initiative is to make the value of software freedom more tangible to people when they’re looking for applications in an app store (e.g. “this app won’t leak your data” instead of “this app is licensed GPLv3+”). On the developer side, the goal is to encourage ethical practices (e.g. encryption) and discourage unethical ones (e.g. tracking). So far we’ve mostly discussed this idea internally at Purism, but as with everything else we’d ideally want it to be a ecosystem-wide thing others can benefit from rather than something we do downstream.
There’s plenty of relevant art for nudging people towards more ethical choices. In other industries there are many examples for both info badges/warnings (e.g. food labels with nutritional information) and indirect incentives (e.g. higher taxes on unhealthy foods). In the software realm, interesting examples include FDroid’s anti-feature warnings, and Terms of Service; Didn’t Read, which has curated summaries and letter grades.
In our case we have limited options in the short term, because we have to deal with multiple different software sources (someone might have apps from a distribution repo, multiple Flatpak remotes, and who knows what else). In addition to that, giving a simple answer to the question “Is this app safe to use?” is often complicated and somewhat subjective. For example, it’s impossible to build an email client that doesn’t send unencrypted messages, or an RSS app that doesn’t connect to servers which could track you. Does that mean we should mark these apps as insecure/unethical?
There currently isn’t a trusted entity which could make the complex value judgements that are involved with deciding whether applications are ethical at scale, for many different software sources.
My feeling is that instead of coming up with a complicated process that may or may not work the way we expect it to, it would be good to first experiment with some leaner solutions and test the general approach. A potential first step we discussed could be something similar to the anti-features on FDroid, perhaps tied in with the existing Appstream metadata we have. In combination with Flatpak sandboxing/permissions there are a number of cases where you can actually say with relative certainty that an app is safe/ethical without complicated judgement calls (e.g. fully sandboxed apps without network access). If we can find a few such categories of apps this could be a good starting point, to see if this helps us reach our goals.
Obviously this needs a lot more work, but I’m hoping to do at least some mockups/prototypes soon. Also, I haven’t talked to a ton of people about this so far, but I imagine other projects with a focus in software freedom/ethics might be interested in this problem as well. If you work on such a project and have ideas/comments/concerns, let’s chat!
Wednesday: Beach BoF!
After 5 intense days of GUADEC and BoFs we had a more chill day at the beach on Wednesday. We still had lots of productive discussions about GNOME stuff there of course, maybe even better in some ways because we didn’t have our laptops distracting us :)
I’d like to thank the organizers for putting together an awesome GUADEC, all of my GNOME friends old and new for being there, and the GNOME Foundation for sponsoring my attendance!
So you’ve decided to make a new app for GNOME, and designed a great interface for it. Now you want to start building it, so you open Gitlab to create a new repository. But then, oh no — it wants a name for the repository. Existential dread sets in.
Naming things is hard, and naming user-facing things is even more so. App names are read, pronounced, heard, and remembered by lots of people. The name is, along with the icon, the most important identifier for your project. With this tutorial I hope to make finding a great name for your app a bit easier.
“An application’s name is vital. It is what users will be first exposed to, and will help them decide whether they want to use an application or not. It is a major part of your application’s public face.”
Finding a good name is not always easy, but putting in a bit of effort up-front is worth it, because renaming the app once it’s established is much harder and messier.
A good name should:
Consist of one or two simple nouns
Be related to the app’s domain (e.g. Celluloid for a video app)
Be short (less than 15 characters)
Be easy to pronounce
Make it easy to come up with a good icon (e.g. by referencing a physical object that could be used as the icon)
Use title case (e.g. Icon Preview instead of iconPreview)
A good name should avoid:
Using trademarks or names of other projects (e.g. GNOME MPV)
Having a “G” prefix (e.g. GParted)
Overly complicated names and acronyms (e.g. GIMP)
Puns and inside jokes (e.g. D-Feet)
Non-standard punctuation or whitespace (e.g. UberWriter)
Made-up words or word combinations (e.g. Inkscape)
Over the years I’ve been involved with naming a lot of projects, and at this point I have a process which consistently produces pretty good results. It more or less goes like this:
Write down all the words related to the app’s domain you can think of
Do a thesaurus search for some of those words to find even more related words
When you have about 15, start picking out some of the best-sounding ones, and look at their other qualities. Are they too long? Easy enough to pronounce? Do they have any unintended negative connotations?
Once you have picked a handful of favorites, do a quick check to see if the names are already taken
Among the ones not taken, pick your favorite one
Of course, when naming an app which is part of GNOME itself, the rules are a little different because these apps have completely generic names describing their function or the type content they show (e.g. Files, Image Viewer, Fonts, Music). That’s a much more rare (and usually easier) case though, so in this tutorial I’ll focus on independent third-party apps.
Let’s look at a real-world example of this process. A few months ago I was involved in renaming an internet radio app. At the time it was called Gradio, which was a bad name for many of the reasons mentioned above, and we wanted a nicer name for the new, completely rewritten version of the app.
So, internet radio. What words immediately come to mind?
These are pretty generic, so let’s branch out a bit. As with most digital technologies it’s hard to find nice metaphors, but we can make use of the analog predecessor to it (i.e. analog radio). Are there physical objects related to that which we could use?
Maybe something related to analog radio technology?
What about names of people who worked on the technology?
Now that we have a few words to start with, let’s plug them into a thesaurus and see if there are any good related words. This is usually pretty hit or miss, as most related words you’ll find will not be relevant to the domain or make sense as names. However, after a few searches I always find a few good options that I didn’t think of before.
Update: I recently found another good website to find related words, appropriately named relatedwords.org.
Here are a few additional words from thesaurus searches:
In this particular case we also had a brainstorming session on Matrix with a group of people from the community, which produced a few more options:
3. Pick the best ones
Now we have about 20 words, which is a good place to stop brainstorming and start looking at which ones would make good names.
This process is not very scientific, just look at each word and imagine it as the name of the app. In particular, pay attention to the length of the name, ease of pronunciation, and whether it sounds nice.
In this case, some of my favorites are:
They’re all relatively short, easy to pronounce, and sound good as app names. The main question at this point is whether we can use them or if they’re already taken.
4. Check if they’re taken
I usually start off by searching directly on Github, to see if there are other FOSS projects already using the name. If I don’t find anything there, I search for the name on on Duckduckgo, adding “app” or “open source”.
In many cases you’ll find something somewhere using the name already. That doesn’t necessarily have to be a problem if it’s an app/project/company in a different domain, but it’s good to avoid large projects and companies.
In this case, it turns out “Transistor” is already a radio app for Android. Since it’s an app doing something very similar, people might think our radio app is affiliated with this project, which we want to avoid.
“Hertz” is the name of a car rental service. It’s a pretty big company, so best to stay away from that as well.
“Spectrum” is already the name of a forum software (which looks really cool btw). The potential for confusion is low, but the project looks well-established with 6000+ stars on Github, so not a great option.
“Shortwave” is used by a bookmarking app, and there are some search results related to actual analog radio software, but nothing that looks big or problematic. This seems like a viable option.
5. Pick a winner
At this point you probably already know which of the viable options you like best, so just go ahead and make it official. In our example,”Shortwave” won because it was short but distinct-sounding, related to the domain, a pronounceable English word, and not taken by any major projects or companies.
If you find that all your favorites are taken, go back to the first steps and do some more brainstorming. The perfect name for your app is out there, and you’ll find it!
Bonus: Good Examples
For inspiration, here are some examples of well-named third party apps in the GNOME ecosystem, and what makes their names great:
Fragments — A torrent app. The name is great because it’s unique among torrent app names (which usually reference water, e.g. Deluge), yet still clearly connected to the domain (BitTorrent splits up files into lots of tiny parts and sends them in random order).
Peek — A GIF screen recorder. The name is very appropriate since the app is for making short recordings of small parts of the screen. The app feels small, quick, and frictionless, which the name perfectly encapsulates.
Teleport — Sends files across the local network. The idea behind Teleport is to make sending a file across the local network effortless compared to other methods, such as using web services or USB drives. Using a sci-fi metaphor in the name lends itself well to that.
So you’re excited about the Librem 5 and GNOME going mobile, and want to start building an app for it. Of course, the first step is to design your app. This can seem quite challenging if you’re just starting out with a new platform, but fear not! In this blog post I’ll walk you through some of the most important UI patterns, and the process of going from idea to mockups step by step. Throughout this I’ll be using a read-it-later app as an example.
The GNOME design philosophy
Before starting to design for a platform, it’s good to familiarize yourself with the design philosophy of the platform. The GNOME Human Interface Guidelines have a “design principles” page which I encourage you to read in its entirety, but will paraphrase a few highlights from here:
Simplicity and Focus — Make sure you have clear goals for your app from the outset, and focus on those. Often it’s better to make a separate application to cover an additional use case rather than cramming too many things into one app (e.g. video podcasts are different enough from audio podcasts to be better off as their own app).
Search and Undo — If there are large amounts of content in your app, provide full-text search to make it easy to find things. Be forgiving about people making mistakes by making it hard to lose data, and never use a warning when you mean undo.
Avoid Preferences — “Just adding an option” often seems like a quick fix, but in most cases you’re just treating symptoms rather than the root cause. It’s better to figure out what that root cause is and fix the problem for everyone, rather than papering over the cracks with a preference. I highly recommend this article by Havoc Pennington on the topic.
Now that we’re full of high-minded ideals, let’s jump into the actual design process. Let’s design a great read-it-later app.
We will follow the GNOME design process, which primarily consists of three steps (plus iterations):
Define goals and non-goals for your app
Collect relevant art, i.e. examples of similar apps to borrow ideas from
Make sketches/mockups of the main views and user flows
1. Define Goals
The app we’re designing is going to be a native client for read-it-later web services (such as Pocket). These services allow you to store articles and other web pages that you are interested in, but don’t have time to read right now. That way you can catch up on all the stuff you saved later on, when you have more time. As such, our primary goals are:
Listing your saved articles
Providing a great, focused experience for reading articles in the app
Helping you actually catch up with your reading list
Storing articles offline, so they can be read without a network connection
Some non-goals, i.e. things that are out of scope for this application:
2. Relevant Art
The next step is to find some examples of existing apps that do similar things. It’s good to look at how other people have solved the same problems, what they do well, and what could be improved before jumping into designing a new app.
So let’s check out the competition:
Pocket on Android has a lot of features, and a pretty complicated interface. It has lots of categories, social features, a discover section, text-to-speech, and much more. I’ve personally never used most of these features, and they make the app feel quite cluttered. In my experience Pocket is also not very good at helping me get through the list of things I’ve already saved. It feels like it mostly wants me to discover new things to save (and then not read).
Clearly there are some lessons to be learned here for our app.
I’ve never used the app myself, but judging from screenshots, Instapaper’s UI feels a lot saner and more focused than Pocket. I also really like the rich article previews in the list view and the nice typography.
Wallabag is a self-hosted alternative to Pocket and Instapaper. This Android client for it (also called Wallabag) is not very sophisticated UI-wise, but it’s a good example of a very simple native client for this kind of service.
Structurally, these apps are all quite similar: a main view with a list of articles, and an article view that just displays the article in a clean, readable format.
Depending on the service, there are multiple lists for different types of articles such as Archive, Highlights, Favorites, Notes, etc. To keep things simple, and because we’re targeting Wallabag first and foremost (since it’s the only self-hosted service), we’re going with only three categories: Unread, Archive, and Favorites.
This means that our application is going to have four main screens we need to design: the three article categories mentioned above plus a reader view, which displays the article content.
Now that we have a basic idea of the structure of the app, we can finally dive into designing the UI. Personally, I like starting off with sketches on paper and then move to Inkscape for more detailed mockups, but you can use any tool you’re familiar with. You don’t need to be good at drawing or a particular application for this, just find a way to visualize your ideas which works for you :)
If you’re using Inkscape for mockups, you might want to check out the GNOME mockup template which contains some common layouts and patterns to use in your designs. If you are looking for GNOME-style symbolic icons for your mockups, you can find them here, here, and here.
When it comes to the layout of an interface, one of the first things to consider is what navigation structure makes the most sense for the type of content you have.
The most common navigation patterns in GNOME apps are the Stack, the View Switcher, and the Sidebar List.
The Stack pattern is when you have completely separate views with no shared UI, and a back button to go back to the overview. This is what Photos does for navigating between the stream of photos and the detailed view of an individual photo, for example. There is a bit more friction to switch between views than with other patterns, but it’s also more focused. This pattern is great for situations where you don’t switch between views a lot.
The View Switcher is for cases where there are a small number of views that are equally important or need to always be easily accessible. It’s used in GNOME apps such as Clocks, Music, and Software as the primary navigation. On the desktop, this switcher is always in the headerbar, but there’s work on a new adaptive version of it, which moves to the bottom of the screen for mobile. This is not quite ready yet, but will hit a version of Libhandy near you soon™.
The Sidebar List is for cases where there are a lot of views that you need to switch between often. For example, it’s used in Fractal for the room list, because it gives an overview of all rooms and allows for quick context switching. Of course, on mobile there’s not enough space for a content pane and a sidebar, so there is a Libhandy widget called Leaflet, which transforms from a Sidebar List on desktop to a Stack on mobile.
For our read-it-later app, we need navigation to switch between the different lists (Unread, Archive, Favorites), and to switch between list and article views.
For the latter we could either use a stack or a sidebar list (using the Leaflet widget so it works on mobile). Since we want this app to be a focused reading experience and switching back and forth quickly between articles is not a very common use case, a Stack is probably the best solution here.
This means that our main screens will look something like this:
Article List Screens
Now that we have a basic navigation structure we can design the individual screens in more detail. The three article list screens are basically the same lists with different content.
The main purpose of these screens is to provide a nice, legible list of the saved articles that entices people to catch up with their reading list. In order to do this we’re going with a comfortable layout including article title, preview, and some information about the article.
To help people catch up with their saved articles, we should also try to make the content as interesting as possible. A simple reverse-chronological list of saved items is quite boring, and I’ve noticed in my own use that I often scroll down the list randomly to discover older articles. A potential way to build this into the core experience would be to show the reading list in randomized order, and show the most recently saved articles at the top in a separate category. I’ve tried that in the mockups below.
In terms of actions, we need to expose search and selection mode (for operations on multiple elements), as well as the application’s primary menu. The primary menu contains global app-level things such as Help, Preferences, and About.
In selection mode we need the ability to move articles to Favorites and Archive, and delete them from our reading list. Since this is not essential functionality though, we won’t be doing designs for it yet. If you want to learn more, have a look at the selection mode page in the GNOME HIG. The same goes for search (relevant HIG page).
The article screen’s job is pretty straightforward: provide a great reading experience for the saved articles. Since many websites kind of suck in this regard, a reader mode (like Epiphany and Firefox have) should be the default view whenever possible. However, since there’s no guarantee that a given article will be rendered perfectly, we need some way to show to the website with its native styling when necessary.
We also need a way to move an article to Favorites and Archive, delete it, and share it. The most important actions are usually exposed directly in the header bar, but for less important actions (or if there’s not enough space), we can use a secondary menu.
We now know more or less what the app looks like on mobile, but what about the desktop? As with responsive web design, if you design your app for mobile first, it’s usually pretty easy to make it work well on larger screens too.
In this case, since we don’t have any sidebars or other complicated layout elements, the main change happening at larger sizes is that the content column width grows with the window, until it reaches a maximum width comfortable for reading. This can be implemented by wrapping the content area in an HdyColumn. The view switcher also moves up to the header bar, and there is a close button on the right side.
What we now have is the basic structure and most important screens of the application, but that’s of course far from everything. We don’t yet have designs for login and account settings, empty states, first run experience, errors, search, and a number of other things. I wanted to stick to the basics for this post, but perhaps I could expand on these things in future blog posts if there’s interest.
It’s also worth noting that mockups are never final, and interfaces almost always change during implementation, as you learn more about use cases, the underlying technology, and other constraints. Ideally you’d also do some informal user testing on real people, and get feedback on the design that way.
I hope this has been useful as an introduction to designing apps for the Librem 5 (and GNOME more generally). If you have any questions feel free to drop by on #gnome-design on IRC/Matrix or the Librem 5 apps Matrix room (#community-librem-apps:talk.puri.sm).
Earlier this month I attended FOSDEM in Brussels. This year was much more relaxed than last year because I didn’t have a talk or other major responsibilities. That meant I had a lot more time to talk to fellow GNOME people and other friends working on different projects.
I spent a lot of time at our booth, talking to people coming by, and planning new projects with fellow developers. The only talk I ended up going to was Zeeshan’s on Rust. I really wanted to go see Jordan’s talk as well, but the Rust devroom was way too packed on Sunday. I also attended the Mobile Free Software BoF, where Nicole gave a status update about the Librem 5 to interested community members, and people could ask questions.
Julian and I also did some work on Fractal, and we had very productive conversations with Adrien and Bilal about adaptive widgets and mobile GNOME apps. I’m very excited about all of these things progressing, and already feel like 2019 is going to be an amazing year for GNOME :)
All in all it was great fun, and I’ll definitely try to go again next year. Thanks to Bastian for organizing the apartment, and the GNOME Foundation for sponsoring my attendance!
Last week I was in Seville, Spain for our second Fractal Hackfest this year. This time it was organized by Daniel Garica Moreno, and held on the University of Seville campus. It was a small event with mostly core developers, focused on driving forward the backend changes and refactoring needed to make our future plans (end-to-end and the app split) possible. We also had some local newcomers join (shoutout to Alejandro Domínguez).
The main reason why we wanted to have another hackfest was to drive forward the long-term effort of making the application more modular, in order to add persistent storage and allow for the app split. The work done over the past few months (such Julian’s room history refactor) has gotten us much closer to that, but there were still some missing pieces and open questions.
During the hackfest we discussed some of these things, and decided, among other things, to split the backend out into a separate crate and move to SQLite for persistent storage. Daniel and Julian already started working on these things, see their blog posts for more details.
GNOME Newcomer Experience
The other focus for the hackfest was discussing an improved GNOME Newcomer experience. Finding the right rooms to join is currently quite confusing, as there is no central directory of all GNOME rooms. The main way people discover rooms seems to be word of mouth or googling for them, which is clearly not great.
Since one of the main goals for Fractal is to provide a more modern alternative to IRC for GNOME developers, we’ve been thinking about how to make it seamless to discover and join GNOME rooms for some time.
In theory Matrix has communities, which would address use cases like this one. However, since the spec for this is not really settled yet, and implementing it would be a lot of work, we’d like to do something simpler for now.
Looking at some relevant art we found Builder’s integration of Newcomer apps on the project screen quite interesting, because it’s very accessible but doesn’t get in the way.
The idea we came up with is combining the newcomer UX with the room directory into a new discovery view, and moving it to a more prominent location in the sidebar. There are still some open questions about how exactly we’d implement this, but it’s an exciting direction to be working towards.
Hacking, Housekeeping, and Best Practices
We did a lot of overdue housekeeping and organizational work, like moving to GNOME/ on Gitlab (thanks Carlos!), getting a new policy for code reviews and QA in place, issue triage, fixing bugs, and starting the process of documenting best practices we’d like contributors make use of.
Lastly, we made a push to fix some of the last outstanding blocker bugs to get a new stable release out the door, which is long overdue (the last release was in September, which is an eternity by our standards). A ton of exciting stuff has landed on master since then: a more legible layout for the message view (using Libhandy’s HdyColumn), smoother message loading, a reorganized header bar with in-window primary menu, and support for large emoji. I’m very excited to finally get these things in the hands of users.
The new release now almost ready, and will be on Flathub very soon. Since there were a lot of big changes under the hood, there will probably be some exciting new bugs as well, so please file issues on Gitlab :)
Thanks to everyone who attended the hackfest, Daniel for organizing, and the University of Seville for hosting us. Thanks also to my employer Purism for sponsoring my travel and accommodation, and the GNOME Foundation, SUGUS, and Plan4D for sponsoring some lunches and dinners. See you next time o/
It’s been an exciting year for Fractal, the GNOME Matrix client. Since our last hackfest in May, we’ve decided to split the application, refactored large parts of the backend, implemented new features such as the media viewer, made the message history adaptive, and laid the groundwork for end-to-end encryption.
Now that we have most of the foundations in place that will enable our long-term goals (such as adaptive layout, E2E, and the app split), we’re getting together again to push these initiatives forward. This is why we’re having another hackfest on December 11-14 in Seville, Spain.
The main focus of the hackfest will be finalizing the backend refactor, and tying up various loose ends related to this, so we can start working on E2E and the app split. The other area we want to focus on is improving Fractal as a tool for GNOME developers, and IRC replacement. In particular, we’re interested in providing a smooth, integrated GNOME Newcomer experience, because finding the right rooms to join is currently a big pain point for new contributors.
tl;dr: If you want to change how an app looks, you need a designer in the loop.
Over the past few months we’ve had a lively debate about “theming” in GNOME, and how it affects our ecosystem. In this discussion I’ve found that there is a divide between people who design and/or develop apps, and people who don’t. I have yet to see an app developer who thinks the current approach to “theming” can work, while many people who aren’t app developers are arguing that it can.
After a few long discussions I started to realize that part of the reason why there’s so little agreement and so much drama around this issue is that we don’t agree what the problem is. Those who don’t work on apps often can’t see the issues with theming and think we want to remove things for no reason, while those who do are very frustrated that the other side doesn’t want to acknowledge how broken everything is.
The basic issue we’re arguing about is whether it’s possible to restyle applications automatically, at scale, without breaking them. In this post I’ll try to explain why I think that it isn’t possible, and why trying to do it is hurting our ecosystem.
There are no themes, just CSS
A fundamental misconception a lot of people have is that GTK 3 supports theming. This is not true, as there is no clearly defined theming API. There are CSS stylesheets, but they were only ever meant to be used by the platform and app developers. The platform stylesheet is called Adwaita (“the only one” in Sanskrit) for a reason.
However, some people (inlcluding major distributions) have been using custom stylesheets as a hacky approximation of “themes” for so long now that nobody even remembers that they are not a real theming API.
Since CSS is a huge API surface, which is used by both app developers and “theme” developers, it’s very easy for the two to conflict. This leads to apps looking broken unless you manually do QA for every app/theme combination.
“You’re exaggerating, it’s not that bad.”
One of the most frustrating things about the current situation is that to users, it looks like it almost works. For the most part, third-party themes look and work okayish, there are just a few small bugs here and there. A button with too little contrast, an underline clashing with a border, a really large loading spinner. Not that big a deal, you’d think.
However, this view of the situation misses a few really important realities:
App developers are doing a lot of bug fixing to account for “theming”, because people complain to them when their app is broken on certain distros. The current situation essentially forces developers to fix bugs for setups they never intended to support in the first place. They’re not happy about it, but they’re doing it because they don’t want their users to have broken apps.
App developers are trying hard not do anything innovative or visual in their apps, because they know it will break with other stylesheets.
“Theme” developers are fixing a lot of bugs for edge cases in individual apps in their stylesheets. Of course, this is a never-ending task because as soon as a new version of an app is released, something will very likely be broken again.
All of this only kinda sorta works because we have very few apps. If we ever hope to grow our ecosystem past a few dozen apps things have to change, because maintaining a “theme” gets less sustainable with every new app.
There is also the question of what your definition of “broken” is. Some people think that things like these are acceptable:
I believe this is nowhere near ok. App developers put a lot of effort into making sure their apps look and feel right, fixing bugs, and doing QA. Having distributors change their apps (often in ways that break things) with no QA before users get to experience them is developer-hostile, and would be unacceptable in any other context.
Can you imagine Samsung restyling every third-party app on their phones, without testing them, and when Instagram complains that the text on their buttons is illegible Samsung just shrug and say “Sorry, but branding is very important to us. Why don’t you change your app?”.
“But it’s fine as long as you follow best practices!”
This is a common sentiment among some people. “If only app developers followed best practices, used CSS variables, and derived their colors from theme colors, everything would be fine”, the argument goes. While it’s true that these things are important and make apps more flexible in terms of appearance, this doesn’t come close to solving the entire problem.
If every app only used default GTK controls, in very simple layouts, with no custom widgets or in-app CSS, then best practices would perhaps be enough to prevent apps from breaking. But the reality is that a) this is not the case, and b) we really don’t want it to be the case.
Human Interface Guidelines are just that: guidelines. They have to be implemented manually, they change and evolve over time, and the best apps on any platform push their boundaries in some places and experiment with new patterns (which then sometimes make their way back into the HIG).
This kind of experimentation means that it’s impossible to “theme” apps automatically. Visual design and interaction design are very closely linked, so if you want to change the style, you need a designer to actually think about what a widget should look like.
For example: How should the Pop theme know what a “flat” variant of the new Nautilus path bar should look like? It’s impossible to do this automatically, because it’s a new pattern.
This is not a rare situation, even among core GNOME apps. Many of the apps I’ve personally worked on have their own equivalent of the Nautilus path bar. And that’s the way it should be. Apps have different needs that sometimes require custom solutions, and this experimentation is good for the ecosystem. However, it also means that automatic restyling is impossible.
“But what about Adwaita Dark and High Contrast?”
The point that the dark and high contrast variants of Adwaita can be seen as GTK 3 kinda sorta supporting themes is technically accurate, but misguided. Adwaita variants may technically just be different stylesheets, but this is just an implementation detail. There are very clear differences between them and third-party “themes”.
They are very very close to Adwaita code-wise, and therefore much less likely to break.
There’s a finite number of them, and they are part of the platform. This makes them a tangible target for developers to test for and support, which is completely different from third-party “themes” which just apply random CSS to every app without any QA.
They are part of the same design language, so they require very little extra work to adapt to from a design point of view. If you follow the best practices mentioned above, often no work at all.
“But what about consistency? I want all my apps to look the same!”
“Consistency” is a word you hear a lot in debates about theming, but it seems to mean different things to different people.
To some, consistency effectively means “everything should use the same colors”. This is relatively easy to achieve for some apps, even across toolkits, if you simply provide a “theme” for each toolkit.
However, this “consistency” is very shallow. Just because a Qt app uses the Adwaita colors it doesn’t automatically fit in with the GNOME platform. UI patterns are much more important, and they can’t be changed with theming. There is no magic that can redesign menu bar apps with header bars.
Real consistency can only happen by design, and requires the app developer to build it into the app at every step. If you want all your apps to look the same, only use apps built for your platform’s HIG. “Fixing” apps after the fact with theming isn’t really making your system more consistent, but it’s hurting app developers a great deal.
Of course, even the very shallow “everything uses the same colors” consistency is impossible to enforce across all apps and toolkits. Apps like Blender, Telegram, or Steam don’t respond to system theming at all, and even Firefox and Chromium only do so in a very limited fashion.
“But users *want* themes!”
“Users” want a lot of things, but just because you want something impossible that doesn’t make it possible. In this case, it’s important to be aware of the costs of giving complete visual freedom to “themes”, both in individual app developer effort, and chilling effects on the ecosystem. If given a choice between customization and more, better apps, I’m confident the majority of people would prefer the latter.
Would it be nice if there were a way to be able to restyle every app to make them look like Material Design, or macOS, or Windows 95, and have them all look as if they were built for that style? Absolutely! I would love that! However, as I’ve tried to explain in this blog post, this is simply not realistic.
So, what can we do?
As the recent discussions have shown, talking about solutions before we agree what the problem is isn’t very productive, so for now I’m mostly interested in making sure we’re all aware of the problem and its various facets. There are several different stakeholders with different perspectives on this issue, and making progress will mean making some hard choices. At this year’s GUADEC we had a Theming & Ecosystem BoF where we talked about a number of potential directions, and I hope we can move forward on that path.
No matter what we come up with though, I think it’s crucial that we start taking the needs of app developers seriously. Developers are the lifeblood of any platform, and we’ve been treating them very poorly. If we want to grow our ecosystem and actually compete with other major platforms, we need to fix that.
Note: The examples in this post have been chosen because the themes in question ship with major distributions, so app developers tend to get complaints about them. It’s not my intention to single them out, this problem applies to all third-party themes equally.
A few weeks ago I attended GUADEC in Almeria, Spain. The travel was a bit of an adventure, because Julian and I went there and back from Italy by train. It was great though, because we had lots of time to hack on Fractal on the train.
The conference days were great, though I didn’t manage to see many talks because I kept getting tied up in interesting discussions (first world problem, I know :D). I did give a talk of my own though, about my work at Purism on UI patterns for making GNOME apps work on mobile. There is a video recording of the talk, and here are my slides.
The main thing I tried to get across is that Purism isn’t trying to create a separate ecosystem or platform, but to make the GNOME platform better upstream. We ship vanilla GNOME on our laptops, and we want to do the same on phones. It’s of course early days, and it will take a while for everything to get into place, but it feels great to work for a company that has upstream-first as a core principle.
The biggest area where our efforts will make an impact upstream in the short term are the Libhandy widgets Adrien and Guido have been working on. These widgets allow regular GNOME/GTK apps to scale to smaller sizes using adaptive UI patterns. The patterns are extending GNOME’s existing HIG in a few small details only, and can be used to make many existing GNOME apps adaptive without requiring major UI changes. We’re still experimenting with them, but once the patterns are solid and the widgets stable, we will work to upstream them into GTK.
Using Libhandy widgets will not only enable apps to run on phones, but also yield benefits on the desktop. For example, HdyColumn solves a very old problem many GTK apps have: Lists that need to grow with the window’s width, but also need a maximum width to ensure legibility. By enabling this, HdyColumn allows apps to work better on both very small and very large screens.
The BoF days were packed with interesting sessions, but sadly many of them happened simultaneously, so I was only able to attend a few of them. However, the ones I did attend were all incredibly productive and interesting, and I’m excited about the things we worked on and planned for the future.
Monday: Librem 5
On Monday I attended the all-day Librem 5 BoF, together with my colleagues from Purism, and some community members, such as Jordan and Julian from Fractal.
We talked about apps, particularly the messaging situation and Fractal. We discussed what will be needed in order to split the app, make the UI adaptive, and get end-to-end encryption. Daniel’s work on the database and Julian’s message history refactor are currently laying the groundwork for these.
On the shell side we talked through the design of various parts of the shell, such as keyboard, notifications, multitasking, and gestures. Though many of those things won’t be implemented in the near future, we have a plan for where we’re going with these, and getting designers and developers in one room was very productive for working out some of the details.
We also discussed a number of exciting new widgets to make it easier to get GNOME apps to work at smaller sizes, such as a new adaptive preferences window, and a way to allow modal windows to take up the entire screen at small sizes.
Multi-Monitor & Theming
On Tuesday we had a Multi-Monitor BoF, where we discussed multi-monitor behaviors with people from System76 and Ubuntu, among others. The most interesting parts to me were the discussions about adding some usecase-driven modes, such as a presentation mode, and a potential new keyboard-driven app switching interface (think Alt-Tab, but good). All of this will require a lot of work, but it’s great to see downstreams like System76 interested in driving initiatives like this.
In the afternoon we had the Theming & Ecosystem BoF, where we got designers, upstream GNOME developers, and people from various downstreams together to talk about the state of theming, and its impact on our ecosystem.
The basic problem we were discussing is that app developers want stable APIs and control over what their app looks like on user’s systems, while some distributions want to apply their own branding to everything. The current situation is pretty bad, because users end up with broken apps, developers constantly need to fix bugs for setups they didn’t want to support in the first place, and distributions need to invest lots of resources into building forever-slightly-broken custom themes. We discussed a number of possible approaches to tackle this problem, in order to make our platform easier to target. I’ll blog about this in more detail, but I’m excited about the possibility of finally solving this long-standing problem.
We also talked about some of our future plans with regard to icons. This includes a new “library” of symbolics, and a push for app developers to ship symbolic icons with their apps, rather than linking to random strings which have to be maintained forever. We also introduced the new app icon style initiative, which will make it drastically easier to make icons because they are simpler, more geometric, and there are fewer sizes to draw. All of this will still develop over the next cycle, since it’s not going to ship until 3.32.
Wednesday: What is a GNOME app?
On Wednesday we had a small but very productive BoF to work on a proposal for a policy for including new apps as part of GNOME, and more generally getting a clearer definition of what it means for a project to be part of GNOME. There is currently no clear process for the inclusion of new projects as part of GNOME, so it doesn’t happen very often, and usually in a very disorganized fashion. This is a problem, because it leaves people who are excited about making new GNOME apps without a clear path to do so.
For example, both Fractal and Podcasts were built from the ground up to be GNOME apps, but still haven’t made it to the GNOME/ group on Gitlab officially, because there’s no clear policy. The new Calls app Bob is building for the Librem 5 is in the same limbo, just waiting around for someone to say if/how it can become a part of GNOME officially.
At the BoF we drafted a proposal for an explicit inclusion policy. The idea is for apps that a follow a set of criteria (e.g. follows the HIG, uses our tech stack) to be able to apply for inclusion, and have some kind of committee that could review these requests.
This is only a very rough proposal for now, but I’m excited about the potential it has to bring in more developers from the wider ecosystem. And of course, as the designer of a half dozen semi-official GNOME apps I’m very selfishly interested in getting this in place ;)
In addition to all of the above, it was great to meet and hang out with so many of the awesome people in our community at social events, beach BoFs, and ad-hoc hacking sessions on the corridor. It’s hard to believe that one year ago I came to GUADEC as a newcomer. This year it felt like coming home.
One of the biggest problems with Fractal at the moment is that 1-1 messaging is pretty terrible. Since the rooms in the sidebar are sorted by most recent activity, high-traffic public rooms (such as GNOME IRC channels) tend to drown out rooms with less traffic, such as 1-1s and small groups. This is problematic because the signal-to-noise ratio in 1-1 chats and small groups tends to be much higher than in high-traffic public rooms. This leaves the user constantly searching for the rooms they care about, while the rooms they don’t care about are always at the top.
One way to solve this problem is having a favorites group for “important” rooms. This is a feature Fractal has had for a while, and it does solve some of the problems with a room list sorted purely by recent activity. However, it only works well for rooms that are important over long periods of time, and needs to be managed manually. 1-1 chats are often brief, and there can be many of them in parallel. Putting them in favorites doesn’t make sense in many cases, as it would balloon the size of the favorites group, and require lots of manual work when starting or ending a conversation.
The “obvious” solution would be doing what Riot does: Having a separate group of 1-1 rooms in the sidebar, and thereby keeping the 1-1 conversations in one consistent place. However, this creates more problems than it solves. In practice, it results in multiple groups of arbitrary length competing for real estate in the sidebar. If you have a lot of 1-1s, this means that you’ll be able to see very few rooms (even when most of the 1-1s are old and not relevant at the moment). In Riot, this group is capped at 10 visible rooms by default, but that’s still not great if you only need 2 of them at the moment. The category can be collapsed, but then you can’t see which 1-1s have new messages, and it also means lots of busywork collapsing/expanding the group. Clearly this isn’t an ideal solution, which is why we were very hesitant to go down this path.
A way out?
As we were discussing this issue over the past few months, I started looking more closely at the way people use different messaging tools. One thing I found puzzling is that despite the fact that Matrix theoretically supports the use cases covered by popular apps like Whatsapp and Telegram, few people are actually using it to replace those apps. Instead, they use it to replace IRC and Slack.
Why? My theory is that most chat rooms fall in one of three categories: Private Chats, which include 1-1s and small groups; Team Chats, which are larger, but still private and invite-only; and Public Rooms, which are basically like IRC.
Team Chats and Public Rooms share many characteristics: Both have relatively high amounts of traffic, and there’s a lot of noise. The main difference is that Team Chats are private and the members rarely change (e.g. a company’s internal Slack), while Public Rooms can be joined by anyone at any time, and there is no expectation of privacy (e.g. #gnome-hackers on IRC).
However, Private Chats have relatively little in common with the other two categories: They are low-traffic, and have little or no noise. This may sound like a small difference, but I think it’s the reason why 1-1s suck in Fractal/Riot/IRC, and why people aren’t using Matrix to replace Telegram.
The Banquet and the Barbecue
I’ve come to the conclusion that one app can’t cover all the use cases that the Matrix protocol supports, and still provide competitive UX. If you design an app to deal with lots of high-traffic rooms (e.g. Riot as it is today), it will suck for 1-1s, so people will use something else for those. Similarly, Telegram is primarily designed for 1-1s and small groups, which is why it’s a terrible experience if you have many high-traffic groups.
If we want Matrix to succeed as more than an IRC/Slack replacement we need multiple apps, each focusing on a distinct use case. For messaging, I think the most important distinction to make is between what I call the Banquet and the Barbecue.
The Banquet is a big, loud place. There are tons of people, and you don’t know many of them. Lots of things are happening all the time, and it’s hard to keep track of everything. This is what Matrix is currently mostly used for. Slack, IRC, and Discord are also all in this category.
The Barbecue is at the other end of the spectrum: It’s a calm, private environment where friends, family, co-workers, and other acquaintances hang out. Conversations are mostly between 2 or 3 people, slow, and often very personal. Telegram, Whatsapp, iMessage, Facebook Messenger, and a myriad of other chat apps are optimized for this use case.
Now, what does this mean for Fractal? After a long discussion on Thursday, we decided to split up Fractal into two separate apps with different interfaces, each containing a subset of the user’s Matrix rooms.
Exactly how rooms will be split between the two apps is not 100% clear yet. 1-1s are clearly Barbecue, public rooms are clearly Banquet, but private groups could go either way. For these cases we may need a way to explicitly move rooms between apps. The distinction should probably be part of the Matrix spec, so the intent for a room to be a Barbecue or Banquet room could be set when creating a room, and persist across devices.
The two apps will share practically all the internals, and even large parts of the interface. However, the split will allow us to do some things differently in each app to optimize the interfaces for the different use cases. Some of the changes we’re considering are a bubble-style message view in the Barbecue app, and more room categories (such as low-priority) in the Banquet app’s sidebar.
How exactly the apps will be branded (and what will happen to the Fractal name we all love) is still being decided, but there is some consensus to move to GNOME-style generic names. The Barbecue app will almost certainly be called “Messages”. For the Banquet app there’s less agreement, but my current favorite is “Discussions”.
The Fractal brand will not go away though: We’re thinking of keeping it around as the name of the community project that develops both GNOME Matrix apps, and/or using it for the backend powering both apps.
There are lots of details to be figured out in this transition, both from a design and an implementation perspective, but I’m very excited about this new direction. If you’d like to join the effort, come talk to us on Matrix.
Note: I have no illusions that this change will magically get everyone to leave Whatsapp/Telegram/iMessage and move to Matrix. In the short term, the goal is simply to make Matrix 1-1s a good experience. That said, if we ever want Matrix to make inroads with the general public, I think a move in this direction is an important precondition.
Last week we had an intense 4-day hackfest in Strasbourg to map out the future of Fractal, a native GNOME Matrix messaging app. The event was held at Epitech in Strasbourg’s old town, and organized by Alexandre Franke. Among the attendees were core Fractal contributors Daniel, Alexandre, Eisha, and Julian, as well as Dorota, Adrien, and Francois from Purism. Special thanks go to Matthew from the Matrix core team for joining us on the first two days.
Our main priorities for the hackfest were to plan the roadmap for the next months, decide on the tasks for our GSoC students (Eisha and Julian), and work on the design of some important missing features, like the room settings.
I personally attended the hackfest in both my role as designer on the Fractal project and as a Purism employee currently working on the apps for the Librem 5. One of the reasons why several members of the Librem 5 team attended the hackfest was that we will need a Matrix messaging app on the phone and wanted to explore a potential collaboration.
The hackfest was extremely productive, so much so that I’ll need multiple blog posts to report on all the things we worked on. Here’s a quick outline of some of the most important things that happened:
We’re splitting the app into two separate apps (more on this in a future blog post)
A big refactor of the backend is happening soon to enable the split
We discussed having a system-level Matrix daemon, which different apps could use as a backend (e.g. the two different messaging apps and a calls app)
Matthew explained that room types will be simplified into 1-1, private groups and public groups in the future (which nicely complements our split). We discussed whether 1-1s should be immutable (they should :P)
Matthew explained how end-to-end encryption and calls work in Matrix, and how we could get them in Fractal
We came up with an initial design for multi-account (which basically consists of an account chooser at startup, and a separate window for each account)
We discussed a design for read receipts. Not quite done yet, but we’re on the right path, I think.
We talked about what it will take to make Fractal work on mobile. Not too big of a problem design-wise, but we’ll need Rust bindings for libhandy and emeus
Eisha will be investigating i18n, because we really want to make the app translatable (currently this is hard to do because we use Rust)
Julian will be working on a big message history UI refactor/redesign, as well as other UI stuff, such as user account settings
There is a huge number of message types we don’t support yet and we discussed the design for most of them (including in-app viewers and a history of sent files)
We fought our way though the garbage fire that is the Join and History settings in Riot, and emerged with a design that isn’t terrible (thanks Dorota and Julian!)
Thanks everyone for attending, Epitech and Alexandre for the venue, and Purism for sponsoring the hackfest! It was amazingly productive to have everyone in one place, and I look forward to seeing you all at GUADEC in July :)
For the past few months, I’ve been contributing to a new group messaging app called Fractal. Its aim is to be so good that we can maybe, eventually, finally replace IRC as the primary communication channel for GNOME development.
IRC is old
Though IRC has been around forever, it’s hardly a good user experience by today’s standards, and can be a significant hurdle to onboarding new contributors (especially non-technical ones). Some of the main issues are:
No easy way to use it from mobile
You can only receive messages while online
Sending images or files is only possible via URL
This has led to some free software projects going so far as to use proprietary services such as Slack. However, even then you’re stuck with an Electron app, which is slow and not integrated with the desktop at all.
Enter the Matrix
The Matrix protocol is a modern alternative to IRC. It provides features such as persistence, inline media, and multi-device syncing. Importantly for GNOME, it is also backwards-compatible to IRC using bridges, allowing us to use the fancy new Matrix features without being cut off from the rest of the community.
Over the past few years, some GNOME developers have started using Matrix, but the lack of a good native client has held back adoption.
And that’s where Fractal comes in: It’s a native Matrix client for GNOME, with an interface focused on the IRC use case (discussions in large, high-volume rooms). We want it to be a fast, native alternative to Slack that can compete on UX, and doesn’t require non-free network services.
I started contributing in late October, when the app was still called Guillotine, and looked like this:
I got involved after Daniel Garcia Moreno, the app’s primary developer, mentioned that he was looking for a designer to help out with his Matrix app on #gnome-design. We then started working on revamping the somewhat haphazardly designed interface, and making it look like a proper GNOME app.
Over the past few months the community has grown from just Daniel and I to over 120 people in our Matrix room, and a number of regular contributors. We’ve redesigned every part of the app (except for the room directory), and added a number of small but essential features, such as invites, room creation, and username autocomplete.
The app now looks like this (though the design is still evolving quite rapidly):
For the past months we’ve mainly been working on overhauling the interface, but we haven’t added many new features. As most of the foundational interface work is done now, we can start planning larger new initiatives.
That’s why next month (May 10th-13th) we’re going to have a Fractal Hackfest in Strasbourg. The core contributors will meet for the first time and discuss exciting new things, such as a better onboarding flow, a new responsive layout, and support for more Matrix features.
Among the people joining the hackfest will be Matthew from Matrix, and some of my coworkers from Purism. It will be a great opportunity for plotting future collaborations.
I’m very happy to announce that I’ve joined Purism. It’s awesome to be working for a company that not only cares about software freedom, but also has Ethical Design as a core principle. My role there is UI/UX designer on the Librem 5, a phone built from the ground up to run free software and GNU/Linux.
As a past user of first Firefox OS and then Ubuntu Touch, I couldn’t be more excited about this. Unlike these previous failed efforts, the Librem 5 is focused on freedom and privacy, because it’s made by people who share that philosophy. It’s using PureOS (a full GNU/Linux distro based on Debian), instead of a completely different technology stack with Android drivers (like Firefox OS and Ubuntu Touch did). To make things even sweeter, the UI will be GTK-based, and we’re using upstream GNOME apps (which we’re adapting with a responsive layout). We’ll also be working on new applications for the phone, such as Calls and Messages, which will work on the desktop as well. We want as much of this work as possible to go upstream, so it can benefit all GNOME users.
It’s still early days, but some of the work around apps should become more concrete in the coming weeks, so expect phone-related discussions in #gnome-design. Let’s make a killer GNOME phone!