The JuliaMono Typeface


JuliaMono is a monospaced typeface designed for programming in Julia and in other text editing environments that require a wide range of specialist and technical Unicode characters.

JuliaMono is:

  • free

  • open-source[1]

  • suitable for scientific and technical programming as well as for general purpose hacking

  • available for MacOS, Unix, and Windows [2]

  • easy to use, simple, friendly, and approachable

  • distributed with a liberal licence [3]

This site uses JuliaMono for all text; if your browser can’t[4] (or you didn’t allow it to) download and display web fonts, you’ll only see the font in action in the images. You’ll see a familiar formation of three dots here when/if the font has been downloaded:

(  )

To download and install JuliaMono, see the instructions here.

Screenshots

Editing code in Juno.

And in VS Code.

And in Vim:

And in Emacs:

Examples

The following examples will be rendered in JuliaMono by your browser (if it’s successfully downloaded the web font versions), so I hope what you see here is close to what I made.

The CSS markup applied to the following code uses two weights of the typeface, JuliaMono-Regular and JuliaMono-Medium, which is a smidgeon bolder:

using Zygote: @adjoint
function ignore(f) try return f() catch e; return 0; end
end
@adjoint function ignore(f) try Zygote._pullback(__context__, f) catch e 0, ȳ -> nothing end
end

There are different weights of JuliaMono, so you can control the amount of contrast you have in your highlighted code: JuliaMono-Regular, JuliaMono-Medium, JuliaMono-Bold, JuliaMono-ExtraBold, and JuliaMono-Black. [5]

(There's are also Latin versions of some of the fonts: these are stripped down versions supporting just the basic MacRoman/Windows1252 character sets, intended for use as place-holders, of interest only if you want to have more control over web font loading in web browsers.)

In the hands of a virtuoso (such as Dr Zygmunt Szpak, the author of the following code fragment[6]), the range of available Unicode characters can be quite expressive:

function T(𝛉::AbstractArray, 𝒞::Tuple{AbstractArray, Vararg{AbstractArray}}, 𝒟::Tuple{AbstractArray, Vararg{AbstractArray}}) ⊗ = kron l = length(𝛉) 𝐈ₗ = SMatrix{l,l}(1.0I) 𝐈ₘ = SMatrix{1,1}(1.0I) 𝐓 = @SMatrix zeros(l,l) N = length(𝒟[1]) ℳ, ℳʹ = 𝒟 Λ₁, Λ₂ = 𝒞 𝚲ₙ = @MMatrix zeros(4,4) 𝐞₁ = @SMatrix [1.0; 0.0; 0.0] 𝐞₂ = @SMatrix [0.0; 1.0; 0.0] for n = 1:N index = SVector(1,2) 𝚲ₙ[1:2,1:2] .= Λ₁[n][index,index] 𝚲ₙ[3:4,3:4] .= Λ₂[n][index,index] 𝐦 = hom(ℳ[n]) 𝐦ʹ = hom(ℳʹ[n]) 𝐔ₙ = (𝐦 ⊗ 𝐦ʹ) ∂ₓ𝐮ₙ = [(𝐞₁ ⊗ 𝐦ʹ) (𝐞₂ ⊗ 𝐦ʹ) (𝐦 ⊗ 𝐞₁) (𝐦 ⊗ 𝐞₂)] 𝐁ₙ = ∂ₓ𝐮ₙ * 𝚲ₙ * ∂ₓ𝐮ₙ' 𝚺ₙ = 𝛉' * 𝐁ₙ * 𝛉 𝚺ₙ⁻¹ = inv(𝚺ₙ) 𝐓₁ = @SMatrix zeros(Float64,l,l) for k = 1:l 𝐞ₖ = 𝐈ₗ[:,k] ∂𝐞ₖ𝚺ₙ = (𝐈ₘ ⊗ 𝐞ₖ') * 𝐁ₙ * (𝐈ₘ ⊗ 𝛉) + (𝐈ₘ ⊗ 𝛉') * 𝐁ₙ * (𝐈ₘ ⊗ 𝐞ₖ) # Accumulating the result in 𝐓₁ allocates memory, # even though the two terms in the # summation are both SArrays. 𝐓₁ = 𝐓₁ + 𝐔ₙ * 𝚺ₙ⁻¹ * (∂𝐞ₖ𝚺ₙ) * 𝚺ₙ⁻¹ * 𝐔ₙ' * 𝛉 * 𝐞ₖ' end 𝐓 = 𝐓 + 𝐓₁ end 𝐓
end

Languages

Here are some samples of various languages[7] :

Ancient Greek Ἄδμηθ’, ὁρᾷς γὰρ τἀμὰ πράγμαθ’ ὡς ἔχει, λέξαι θέλω σοι πρὶν θανεῖν ἃ βούλομαι.
Bulgarian Я, пазачът Вальо уж бди, а скришом хапва кюфтенца зад щайгите.
Catalan «Dóna amor que seràs feliç!». Això, il·lús company geniüt, ja és un lluït rètol blavís d’onze kWh.
Czech Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů
Danish Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Walther spillede på xylofon.
English Sphinx of black quartz, judge my vow.
Estonian Põdur Zagrebi tšellomängija-följetonist Ciqo külmetas kehvas garaažis
Finnish Charles Darwin jammaili Åken hevixylofonilla Qatarin yöpub Zeligissä.
French Voix ambiguë d’un cœur qui au zéphyr préfère les jattes de kiwi.
German Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.
Greek Ταχίστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός.
Guarani Hĩlandiagua kuñanguéra oho peteĩ saʼyju ypaʼũme Gavõme omboʼe hag̃ua ingyleñeʼẽ mitãnguérare neʼẽndyʼỹ.
Hungarian Jó foxim és don Quijote húszwattos lámpánál ülve egy pár bűvös cipőt készít.
IPA [ɢʷɯʔ.nas.doːŋ.kʰlja] [ŋan.ȵʑi̯wo.ɕi̯uĕn.ɣwa]
Icelandic Kæmi ný öxi hér, ykist þjófum nú bæði víl og ádrepa.
Irish Ċuaiġ bé ṁórṡáċ le dlúṫspád fíorḟinn trí hata mo ḋea-ṗorcáin ḃig.
Latvian Muļķa hipiji mēģina brīvi nogaršot celofāna žņaudzējčūsku.
Lithuanian Įlinkdama fechtuotojo špaga sublykčiojusi pragręžė apvalų arbūzą.
Macedonian Ѕидарски пејзаж: шугав билмез со чудење џвака ќофте и кељ на туѓ цех.
Norwegian Jeg begynte å fortære en sandwich mens jeg kjørte taxi på vei til quiz
Polish Pchnąć w tę łódź jeża lub ośm skrzyń fig.
Portuguese Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português.
Romanian Înjurând pițigăiat, zoofobul comandă vexat whisky și tequila.
Russian Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства.
Scottish Mus d’fhàg Cèit-Ùna ròp Ì le ob.
Serbian Ајшо, лепото и чежњо, за љубав срца мога дођи у Хаџиће на кафу.
Spanish Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más champaña del menú.
Swedish Flygande bäckasiner söka hwila på mjuka tuvor.
Turkish Pijamalı hasta yağız şoföre çabucak güvendi.
Ukrainian Чуєш їх, доцю, га? Кумедна ж ти, прощайся без ґольфів!

Unicode coverage

One of the goals of JuliaMono is to include most of the characters that a Julia programmer would reasonably expect to find. (Except for all those emojis - they are best handled by the operating system.) Here’s a thousand or so chosen at random:

Unicode sampler

In JuliaMono, every character is the same width, because this is a monospaced typeface. Usually, typefaces with a lot of Unicode mathematical symbols are not monospaced, because they’re intended for use in prose and \( \LaTeX \) applications, rather than in programming code.

From a design perspective, forcing every character into the same size box is a problem. It’s like fitting every human being of whatever shape or size into identical airplane seats - some characters are bound to look uncomfortable. There’s never quite enough room for a nice-looking “m” or “w”.

UnicodePlots.jl uses various Unicode characters to plot figures directly in a terminal window. [8]

ImageInTerminal.jl is similarly awesome, conjuring images from Unicode characters:

JuliaMono is quite greedy[9], and contains a lot of Unicode glyphs.

silly barchart

(Of course, size isn’t everything - quality can beat quantity, and other fonts will offer different experiences[10]).

It’s also a good idea to support box-drawing characters and DataFrames.jl output (terminal permitting):

julia> df = DataFrame(A=samples, B=glyphs)
df = 10×2 DataFrame
│ Row │ A │ B │
│ │ String │ String │
├─────┼────────────────┼─────────────────────┤
│ 1 │ sample 1 │ ▁▂▁▁▂▄▅▁▄▁▁▅▆▂▇▅▂▇ │
│ 2 │ sample 2 │ ▁▂▄▁▁▃▁▆▂▆▃▁▂▃▂▇▄ │
│ 3 │ sample 3 │ ▁▆▇▁▃▇▇▆▅▅▄▇▇▅▅▇▄▂ │
│ 4 │ sample 4 │ ▅▁▄▁▆▃▁▃▇▂▂▇▅▇▃▆▃▁ │
│ 5 │ sample 5 │ ▆▂▁▂▇▆▃▅▅▄▆▇▄▇▆▁▇ │
│ 6 │ sample 6 │ ▁▁▇▂▂▇▃▅▂▂▆▂▄▄▁▄▂▇▆ │
│ 7 │ sample 7 │ ▂▃▂▁▁▇▁▂▆▂▁▇▁▄▃▂▁▄ │
│ 8 │ sample 8 │ ▄▄▁▂▄▁▅▁▅▁▂▂▇▂▁▃▄▄ │
│ 9 │ sample 9 │ ▁▁▁▂▁▆▃▄▄▁▂▂▃▂▁▅▁▆▃ │
│ 10 │ sample 10 │ ▁▇▄▂▅▃▇▁▇▇▆▄▇▅▄▂▄▅▄ │

(Can you spot the little used and sadly mathematically-unsupported "times" character?)

If you want to know whether you can use a Unicode character as an identifier in your Julia code, use the undocumented function Base.isidentifier(). So, for example, if you have the urge to use a dingbat (one of the classic Herman Zapf dingbat designs), you could look for something suitable in the output of this:

julia> for n in 0x2700:0x27bf Base.isidentifier(string(Char(n))) && print(Char(n)) end
✀✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺
✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧➔➕➖➗➘➙➚➛➜➝➞➟➠➡
➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿ julia> ❤(s) = println("I ❤ $(s)")
❤ (generic function with 1 method) julia> ❤("Julia")
I ❤ Julia

Contextual and stylistic alternates

JuliaMono is an OpenType typeface. OpenType technology provides powerful text positioning, pattern matching, and glyph substitution features, which are essential for languages such as Arabic and Urdu. In English, OpenType features are often seen when letter pairs such as fi in certain fonts are replaced by a single glyph such as . These ligatures have been used ever since printing with moveable type was invented, replacing the occasional awkward character combination with a better-looking alternative.

To be honest, I’m not a big fan of their use in coding fonts (and I’m not the only one[11]). I like to see exactly what I’ve typed, rather than what the font has decided to replace it with. But, there are a few places in Julia where suitable Unicode alternatives are not accepted by the language, and where I feel that the ASCII-art confections currently used can be gently enhanced by the judicious use of alternate glyphs. There are also a few places where some subtle tweaks can enhance the readability of the language without introducing ambiguity.

In JuliaMono, the following substitutions are applied when the contextual alternates feature is active:

typed

displayed

-> ->
=> =>
|> |>
<|<> <|<>
:: ::

You can see these in action in the following code fragment:[12]

julialang = true # (!= 0)
(x, y) -> (x + y)
f(p::Int) = p * p
@inbounds if f in (Base.:+, Base.:-) if any(x -> x <:> "addition", Base.:- => "subtraction", ) end
end
df2 = df |> @groupby(_.a) |> @map({a = key(_), b = mean(_.b)}) |> DataFrame # <|<>

OpenType fonts also offer you the ability to choose different designs for certain characters. These are stored as a ‘stylistic set’.

All the options are stored in the font, and are often referred to by their internal four letter code (not the best user-oriented design, really). For example, the contextual alternates listed above are collectively stored in the calt feature.

Sometimes, an application will show the options more visually in a Typography panel[13], usually tucked away somewhere on a Font chooser dialog.

Here’s a list of the stylistic sets currently available in JuliaMono.

feature code

off

on

description

zero 0 0

slashed zero

ss01 g g

alternate g

ss02 @ @

alternate @

ss03 j j

alternate j

ss04 0 0

alternate 0

ss05 * *

lighter asterisk

ss06 a a

simple a

ss07 ` `

smaller grave

ss08 -> ->

distinct ligatures

ss09 f f

alternate f

All this fancy technology is under the control of the application and the operating system you’re using. Ideally, they will provide an easy way for you to switch the various OpenType features on and off.

Browser-based editors such as Juno and VS Code support many OpenType features in their editor windows, but not in the terminal/console windows. They provide a settings area where you can type CSS or JSON selectors to control the appearance of features, and you’ll have to know the feature codes. Some features are opt in, others are opt out; this too can vary from application to application.

Terminal/console applications also vary a lot; on MacOS the Terminal and iTerm applications try to offer controls for OpenType features, with varying degrees of success. On Linux, some terminal applications such as Kitty offer quite good support, but others such as Alacritty offer little or none, as yet. [14]

If the application allows, you should be able to switch the calt contextual ligatures off, particularly since quite a few people won’t like any of them in their code. For the following listing, I switch the calt set off using CSS (see here), and then enable some of the alternative stylistic sets: compare characters such as the 0, g, a, j, and @ with the previous listing:

julialang = true # (!= 0)
(x, y) -> (x + y)
f(p::Int) = p * p
@inbounds if f in (Base.:+, Base.:-) if any(x -> x <:> "addition", Base.:- => "subtraction", ) end
end
df2 = df |> @groupby(_.a) |> @map({a = key(_), b = mean(_.b)}) |> DataFrame # <|<>

(I originally liked the idea of a more circular @ sign, but in practice it doesn’t work at small point sizes, as the details disappear. But I’ve kept it anyway.)

Private Use Areas (PUAs)

There are a few areas of the Unicode system that have been officially kept empty and are thus available to store characters that are not part of the standard. These are called the Private Use Areas, and there are three: \ue000 to \uf8ff, \UF0000 to \UFFFFD, and U100000 to U+10FFFD.

Each typeface can do its own thing in these areas. In JuliaMono, for example, if you look around \ue800 you’ll find a few familiar shapes:

julia> foreach(println, '\ue800':'\ue802')




The obvious drawback to using characters in a Private Use Area is that you have to have installed the font wherever you want to see them rendered correctly, unless they’ve been converted to outlines or bitmaps. If the font isn’t installed (eg on github), you have no idea what glyph - if any - will be displayed.

You can define these to be available at the Julia REPL. For example, say you want the Julia circles to be available in the terminal when you type \julialogo in a Julia session with the JuliaMono font active. Run this:

using REPL
REPL.REPLCompletions.latex_symbols["\\julialogo"] = "\ue800"

Now you can insert the logo in strings by typing \julialogo:

julia> println("Welcome to ")
Welcome to 

It’s usually possible to type Unicode values directly into text. This is a useful skill to have when you’re not using the Julia REPL... On MacOS you hold the Option (⌥) key down while typing the four hex digits (make sure you’re using the Unicode Hex Input keyboard). On Windows I think you type the four hex digits followed by ALT then X. On Linux it might be ctrl-shift-u followed by the hex digits.

Type anything here. Nobody’s looking.

Thanks!

Thanks to: Thibaut Lienart for his Franklin.jl web site builder; to Jérémie Knüsel who provided invaluable suggestions and advice; to Dr Zygmunt Szpak for his cool maths code; to Simeon Schaub for the issues and PRs.

[1]   “open source” Eventually, but I’ve got to work out how to do it first.
[2]   “Windows” For more information about if and how it works on Windows, read this, but I currently don't know enough about Windows font technology and how it differs from MacOS and Unix. Early reports said that the font didn't look good on Windows. This was because the format was CFF/PostScript OTF, which isn't hinted on Windows. A switch to TTF/TrueType OTF, which is hinted, was considered an improvement.
[3]   “licence” Although not MIT-licensed like Julia, JuliaMono is licensed using the SIL Open Font licence, which allows the fonts to be used, studied, modified, freely redistributed, and even sold, without affecting anything they’re bundled with.
[4]   “downloading font problems” The problem might be something to do with the web security feature called CORS which prevents a web page accessing the resources it needs.
[5]   “masters” In fact there are only three masters (Light, Regular, and Black), and three instances (Medium, Bold, and ExtraBold), which are interpolated between them.
[6]   “maths in code” spotted here
[7]   “languages” Please open an issue on Github if there are any problems. I don’t speak most of these languages.
[8]   “terminals and line spacing” Terminal applications usually provide the option to vary the line spacing. For perfectly smooth Unicode plots, you can adjust this until the shaded glyphs are in tune. But for coding purposes you might want the line spacing increased (or decreased) from the default, depending on the trade-off between reading speed, font size, and how many lines of code you can cram in.
[9]   “greedy” referencing this classic Julia blog post
[10]   “better fonts...” Operator Mono and Fira are good typefaces... Try them! Also try IBM Plex Mono, Iosevka, Recursive, and Victor Mono, to name a few. Like programming languages, every typeface has its strengths and weaknesses.
[11]   “not the only one” Matthew Butterick says “hell no” to them. He also uses the phrase “well-intentioned amateur ligaturists” which isn’t a label I want to have. But more seriously, he says: “my main concern is typography that faces other human beings. So if you’re preparing your code for others to read — whether on screen or on paper — skip the ligatures.”
[12]   “alternate glyphs” Note that the substitute glyphs occupy the same width as the source glyphs they're replacing. While you could in theory use one of the thousands of Unicode arrows, such as →, as a replacement for the ‘stabby lambda’ (->), these are the width of a single character, and so you'd be changing the width of your string/line whenever you made the substitution.
[13]   “Typography panel” These vary widely in their abilities and functions: the MacOS Terminal app’s Typography panel is comprehensive but I’m not convinced that all the buttons are wired up yet...
[14]   “terminals again” Writers of terminal apps usually have their own ideas about how fonts and type should be managed and displayed. I haven’t yet found one that did everything that I wanted it to and nothing I didn’t expect it to. In the world of fonts, nothing is 100% correct, which can be frustrating. You can track some of the issues and discussions on github and elsewhere: here’s a VS Code issue; here are the Alacritty terminal developers working on it; here is the iTerm documentation talking about performance.