Samiser

Getting Creative With Pywal

Published Aug. 5, 2019, 8:35 p.m. by sam

What is Pywal?

Pywal essentially functions as a Desktop Background setter like feh, but while setting the background it generates a colour palette from the dominant colours of the image used. It then immediately applies these colours as your system's colour scheme using Xresources, changing the colours of any program that uses the Xresources colours immediately. You can find more information on the Github

Pywal Colours Loaded

It works very nicely and is a really effective and easy way to immediately apply a consistent aesthetic across several applications. However, the really interesting stuff comes from the ways you can manually expand and integrate the pywal colours into your system.

Pywal Colour Scheme Files

As well as loading the colour scheme into Xresources pywal also generates themes for many different programs that aren't necessarily activated by default or need some kind of manual configuration. These are found at ~/.cache/wal/

Screenshot of ls cache wal

In the above screenshot you can see a lot of different application specific colour scheme files listed as well as some more generic file type like json and yml. An application that I use a lot is rofi which, among other things, functions as a program launcher.

As you can see in the screenshot above there are a few themes for rofi in the predefined templates. I'm only really interested in the dark theme because it's more in line with how I've configured my i3 colours (using pywal).

Gif of default pywal rofi dark themes

This theme is nice and it goes well with the colours, but it's not quite how I would like it. I prefer a thinner box and ideally transparency. Fortunately, pywal allows for the templating of these files. In the pywal repo there is a folder of all default theme templates. If you copy one of these files to ~/.config/wal/templates/ pywal will then use that file as the template instead of the default, allowing you to customise it.

Custom Rofi Theme

So looking at the rofi config template we can see a section describing the window:

Default pywal window config

The rofi man page says that you can run rofi -dump-config to get all of the configuration options. Then by grepping for width we can see that width is just defined by width: 50;. So in the template we can change the width of the window by defining the width according to this format:

Thin pywal window config

I found 500 works best for me. The rofi window now looks like this:

Thinner rofi window

Better, but I still wanted transparency. Looking back at the default rofi config template it looks like most of the background colours were either defined by the @background variable or the @foreground variable. These variables are defined on lines 24 & 25 with {background} and {foreground} respectively. This is fairly typical syntax for python string formatting, and looking in the pywal docs confirms this.

Also described in the docs are modifiers that can be applied to the variables that will be replacing the {variable} tags. By default just using {color2} for example outputs a hash with a hex code eg. #FFFFFF. You can instead however use {color2.rgb} to, as you might guess, output the colour in rgb eg. 255,255,255.

Since I wanted transparency I knew the colour would need an alpha value. There is an option to output the variable in rgba format but then I couldn't manually override the alpha value. I ended up with this:

background: rgba({background.rgb},0.7);

so I'm using the rgb modifier to output the colour in rgb format but wrapping that in an rgba format while defining my own alpha value. In this case the alpha value is 0.7 so the window would be 70% opaque. This gave me this result:

Rofi almost there

Not quite what I'm looking for. Having the background variable as semi-transparent means that each element's background stacks up to more opaqueness. I just want a consistently transparent background and opaque foreground elements. I ended up setting the background variable to having an alpha of 0 but gave the background-color variable in the #window settings an alpha of 0.7 using an independent substitution of the background variable. So the changed settings are:

Final rofi config

And the final look of rofi with a few different backgrounds is:

Final rofi

Nice, that's exactly what I wanted. Transparent and thinner.

Startpage Colours

A startpage is just a website that you run just for yourself that is your browser's homepage. it can be anything really, but for mine I've got a search bar that you can either use to access different selections of links or search DuckDuckGo. It's good fun.

Pywal nicely enough generates a CSS file of the pywal colours as CSS variables that can be imported to other CSS files and used there. It also provides a variable for the full path of the background image. I decided to try and use this file in my startpage.

My startpage files are being served to localhost by an apache2 webserver. The files are in /var/www/html. The pywal CSS file is in /home/sam/.cache/wal/colors.css. So I just created a symlink in my css folder to the colours.css file in the pywal cache then imported the file to my main style.css file and finally used those colour variables to style the colours of my search bar.

Coloured search bar

Nice. Now I wanted to use the background variable to set the background image of my startpage as my desktop wallpaper. This proved a bit more difficult as you can't just use CSS to load in arbitrary files from anywhere in the system (for obvious reasons) so I had to use a kind of work around...

Since only the absolute path of the background image was provided, I just created that path in my website's folder. Specifically home/sam/Pictures. Then for the final folder, /wallpapers, I created a symlink to the wallpapers folder in my actual ~/Pictures folder. So the absolute path would actually be a path on the webserver leading to a symlink to my real wallpapers folder where it can get the images.

Kind of a weird hack but it's a local webserver only serving me so it doesn't really matter. If you can think of a better way to do this please dm me on twitter and tell me.

Here are some diff screenshots of the startpage:

Day 1 startpage

Day 2 startpage

It works really nicely in my opinion.

DuckDuckGo Colours

The final thing I wanted to try was changing the DuckDuckGo colours using the pywal colours. I was aware that DuckDuckGo stores themes on your system with cookies so I wanted to see if I could maybe change the colours on the fly by modifying the cookie or something.

However, while looking into it, I discovered that DuckDuckGo allows you to encode the colour theme in the URL. Since I was already using JavaScript to launch the DuckDuckGo search by putting what is in my search box in the url search query variable, this discovery made things a lot easier.

All I had to do was use JavaScript to grab the CSS variables that were already imported through the previous CSS endeavours. This was done like this:

let url_colour = getComputedStyle(document.documentElement) .getPropertyValue('--colour5');

This would store the hex value of colour5 in url_colour. I grabbed a colour variable for each possible DuckDuckGo colour parameter (background, title, description, url, visited) and then encoded them into the url along with the search term:

Url encoding colours

This gave some nice results:

Day 2 DuckDuckGo

Day 3 DuckDuckGo

You can find out more about DuckDuckGo url parameters here.

Conclusion

Pywal is great. I feel like I've still only scratched the surface of using it in different ways for different applications. I hope this inspires you to try playing about with it on your own system.

Thanks for reading.

back