HUIJZER.XYZ

# Creating a reproducible favicon

2022-04-11

Generating a favicon, that small icon that you see in the browser tab, typically involves opening an image editing program and clicking around. I'm not really a fan of clicking because it is hard to reproduce once you want to change something later. This post will show how to make a favicon via the Julia programming language. All tools used in this post are free and open source. You can open this notebook yourself via the link at the bottom of the page and use it to create your own icons and logos.

As color palette, let's use the colors from the Julia logo because they are nice and shiny.

using ColorTypes: RGB
julia_color = Dict(
"blue" => RGB(77/255, 101/255, 175/255),
"red" => RGB(201/255, 60/255, 50/255),
"green" => RGB(59/255, 150/255, 71/255),
"purple" => RGB(145/255, 89/255, 162/255)
);

## The Julia logo

As a first example, let's recreate the Julia logo:

using CairoMakie
julia_logo = let
fig = Figure(; resolution=(480, 240))
ax = Axis(fig[1, 1])

text!(ax, "Julia"; position=(1.4, 1), textsize=150)

markersize = 25

# Two white dots to cut off a bit from the J.
scatter!(ax, (1.4, 8); color=RGB(1, 1, 1), markersize=120)
scatter!(ax, (1.58, 7); color=RGB(1, 1, 1), markersize)

scatter!(ax, (1.58, 6.8); color=julia_color["blue"], markersize)
scatter!(ax, (2.8, 6.4); color=julia_color["red"], markersize)
scatter!(ax, (2.9, 7.4); color=julia_color["green"], markersize)
scatter!(ax, (3, 6.4); color=julia_color["purple"], markersize)

limits!(ax, 1, 4, 1, 9)

hidespines!(ax)
hidedecorations!(ax)

fig
end

Great succes. This image looks a bit different from the real logo because I couldn't use the HN Latin font; a font which is only bundled by MacOS.

Let's go on and make the favicon for this website.

## A favicon for this website

For my blog, I wanted to have something with fx written in a fancy way. Thanks to the reactivity of Pluto.jl, making the following took only 30 minutes:

size = 480;
favicon = let
backgroundcolor = :transparent
# We do a big figure first and scale it down later.
fig = Figure(; resolution=(size, size), backgroundcolor)
ax = Axis(fig[1, 1]; backgroundcolor)

linewidth = 30
fx = 2:0.001:9
fy = [x < 7 ? 2.5 + 0.0255x : 2.15 + 0.1 * (x - 5)^2.4 for x in fx]
lines!(ax, fy, fx; linewidth, color=julia_color["blue"])

fx = 5.5:0.001:7
fy = 3 .+ 2 .* (fx .- 6)
lines!(ax, fy, fx; color=julia_color["blue"], linewidth)

fx = [4.5, 7.5]
fy = [2.2, 5.5]
lines!(ax, fx, fy; color=julia_color["blue"], linewidth)

fx = [4.5, 7.5]
fy = [5.5, 2.2]
lines!(ax, fx, fy; color=julia_color["blue"], linewidth)

limits!(ax, 1, 10, 1, 10)
hidespines!(ax)
hidedecorations!(ax)

fig
end

To turn the plot into a favicon, scale it down and store it as a PNG file. I chose 48 by 48 pixels because that is a reasonable balance between having a small image but also sharp image. Furthermore, I chose PNG because most browsers support PNG files as favicon and it allows setting a transparent background.

favicon_path = joinpath(dirname(dirname(@__DIR__)), "_assets", "favicon.png");
let
mkpath(dirname(favicon_path))
save(favicon_path, favicon; px_per_unit=48/size)
end;

This image can now be linked in the header of an HTML page via

<link rel="icon" href="/assets/favicon.png">

And there we have it, a reproducible favicon 🎉.

## Bonus

To provide you with more inspiration, I recently made the following for a package built around statistical models:

logo = let
fig = Figure(; resolution=(size, size), backgroundcolor=:transparent)
ax = Axis(fig[1, 1]; backgroundcolor=:transparent)

cluster(x::Int, y::Int) = Point2f.([x - 1, x, x + 1], [y, y + 2, y])

markersize = 50

scatter!(ax, cluster(2, 2); color=julia_color["red"], markersize)
scatter!(ax, cluster(5, 4); color=julia_color["green"], markersize)
scatter!(ax, cluster(8, 6); color=julia_color["purple"], markersize)

limits!(ax, 0, 10, 1, 9)

lines!(ax, [0.2, 9.8], [1.2, 8.8]; color=julia_color["blue"], linewidth=8)

hidespines!(ax)
hidedecorations!(ax)

fig
end

Feel free to use these examples as inspiration for your own logos.

## Appendix

Built with Julia 1.7.3 and

CairoMakie 0.7.5
ColorTypes 0.11.0

To run this blog post locally, open this notebook with Pluto.jl.