The source can be found at MonoidMusician/blog on GitHub.
I fell in love with this font upon seeing its Bēhance gallery page. Turns out, my friend and I had also already settled on it for their website! Itʼs a modern, more angular/precise cut of the classic Garamond family. Itʼs a bit risky at body font sizes, but its Garamond OpenType font features assist in keeping it legible, and I went for a more generous font size and weight.
I adore the Upright style, an unslanted italic that has served great in places where I need a more cursive vibe without the semantic implications of a slanted italic.
I had some trouble finding the right source for the files. The latest commit in the GitHub repo seems broken: at least on Mac, the even-odd rule was broken, making the cross-braces on “A” and “e” cut into the figures, which not only looked funny at high resolutions but also destroyed the hinting at low resolutions, almost making the cross-braces disappear. I think I ended up going with the version downloaded from Google Fonts, which contains all of the OpenType features though the font served on their CDN does not.
At the time of writing, non-essential OpenType features aren’t included in web fonts served via Google Fonts’ API; however, the OpenType features are still present in the downloadable fonts, which can then be self-hosted.
I used this purely to supplement Cormorant with Greek characters, which otherwise only contains Latin and Cyrillic.
I do this by making it the default font, coming before Cormorant, but only loading the Greek section of it by chopping down the default Google Font loader. This is necessary because Comorant actually does contain a few Greek characters, like π (compare π in EB Garamond), so we need EB Garamond to override those for the sake of consistency.
body {font-family: "EB Garamond GR", "Cormorant", "Apple Color Emoji";
}
/* greek-ext */
@font-face {
font-family: "EB Garamond GR";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ebgaramond/v25/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7e8QL9xU661hGFJRvzr2Q.woff) format("woff");
unicode-range: U+1F00-1FFF;
}/* greek */
@font-face {
font-family: "EB Garamond GR";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ebgaramond/v25/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7e8QL9-U661hGFJRvzr2Q.woff) format("woff");
unicode-range: U+0370-03FF;
}/* greek-ext */
@font-face {
font-family: "EB Garamond GR";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ebgaramond/v25/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-6_RkCI95WamXgHlIbvw.woff) format("woff");
unicode-range: U+1F00-1FFF;
}/* greek */
@font-face {
font-family: "EB Garamond GR";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ebgaramond/v25/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-6_RkB495WamXgHlIbvw.woff) format("woff");
unicode-range: U+0370-03FF;
}
greek
and greek-ext
URLs only differ by 1 or 2 characters – ask me how I learned that(The hard way).)
Iʼve been using Hasklig for a couple years for my personal coding, but as I was looking for a good font for this blog I found Fira Code on Google Fonts. I started using it for my personal coding too – after all, if Iʼm going to use it for my blog I should find it good enough to use myself!And I have been satisfied with the experience.
At first I thought I would be able to use the Google Fonts hosted version, but due to the same reason as above that did not work out due to the lack of OpenType features.
I needed finer control over the ligatures Fira Code was using.
In particular, PureScript uses the backwards fat arrow <=
for class declarations, which Fira Code can render like that but by default renders as a less-than-or-equals sign <=
.
This is controlled with stylistic set cv20
, so I set font-feature-settings: "cv20" 1
on this blog, since I think <=
is less confusing than <=
– but of course a context-sensitive approach would be better.
I am also tempted to make my own version of the font with visible spaces, but I donʼt yet have enough experience with the font building tools to do that yet.
Used for nonterminals and rule names in grammars.
I needed something with a lot of contrast from Fira Code, which basically meant tall and skinny. It doesnʼt have a lot of characters though, just Latin, Cyrillic, and ASCII symbols (no arrows unfortunately).
Pandoc is cool because itʼs written in Haskell and does what I need. It supports lots of nice Markdown features, seems to have a sane data model, and is pretty easily extensible. I knew that optimizing for SSR static content that doesnʼt require JS was one of my design goals, so thatʼs why itʼs great.
Pandoc includes a builtin Lua scripting language for extensions that transform the content, as opposed to slow external scrips that need to serialize the whole document back and forth.
I tried using some third party scripts, but I ended up rewriting them in Lua:
Ported the script that used python to call node! Ugh that was unnecessary indirection.
I added caching and trimmed the trailing space from the KaTeX output, which otherwise would appear as unwanted space between KaTeX-rendered numbers and their suffixes or whatnot in inline math output.
Running it with npx
was slow, so I cached the binary location from that, but that didnʼt work on the server which immediately deleted the temporary installation or something, even though I thought I had a non-temporary installation.
Who knows.
I also implemented SSR for some of my extensions.
<noscript>
tags.
Uses parse5 to parse the raw HTML embedded in the Pandoc and the node canvas library (based on Cairo!) to run the canvas.
It renders to a default size based on the attributes, e.g. <canvas data-graph="[x => x]" class="pixelated" width="1000" height="500" style="width: 100%;"></canvas>
.
I wanted Pandoc/Markdown content to be primary, but I also wanted to make interactive blog posts with embedded widgets written in PureScript.
The widgets are embedded with Pandocʼs fenced divs (which embed unknown attributes as data attributes) and then they are instantiated with a PS helper that scans for the selector [data-widget]
.
Widgets are wired up to shared datasources based on the provided data-widget-datakey
, making it nice and modular across a whole page:
:::: widget-group
::: {widget="Widget.Control" widget-datakey="main"}
:::
::: {.widget widget="Parser.Grammar" widget-datakey="default" widget-loading="true"}
::: ::::
The dashboard mode is implemented all in CSS, and is the first time Iʼve actually used {display: contents}
to reach inside elements.
In particular, we need to peek through <section>
tags and .widgets
and .widget-group
classes and gather their children to throw directly into the top-level {display: grid}
container (usually the <body class="focus-mode">
element).
I like Sass, most significantly for the color manipulation functions and also the syntax. Of course the nested selectors in Sass/SCSS is a huge convenience for DRY, plus I find the braceless syntax of Sass a little nicer to work with quickly, but syntax support in editors seems abysmal for some reason I donʼt understand. Maybe SCSS support is better just because the syntax definitions could be based on CSS and extended.
SCSSAnd by extension Sass – since SCSS includes certain novel features and Sass merely includes a new syntax, I should mention the new features by the name SCSS for brevity. really needs antiquotation for selectors, attributes, and other core parts of syntax.
That is, since SCSS is 90% a glorified string concatenation library – mainly running on manipulating strings – one of its key usefulnesses is in providing feedback (e.g. in the form of syntax highlighting) on whether the user has entered sensible strings.
So it would be great to have helpers like $sel: syntax.selector(details > :not(summary))
to quote that selector expression into $sel: "details > :not(summary)"
so it can be used in metaprogramming (i.e. passed to the rest of the utility of SCSS) while maintaining the syntactic discipline and feedback of the selector class specifically.
As a specific example, SCSS docs themselves recommend this helper function (to paste over other limitations of their implementation of selector extension with &
).
But in doing so you lose the semantic intention that $child: "input"
means a selector specifically, so if you misspell it you will not have any quick feedback to correct the issue.
Even notice how &
is not highlighted as an operator inside selector.unify
, since it is just treated as an unquoted string literal, not as a selector specifically.
@use "sass:selector"
@mixin unify-parent($child)
@at-root #{selector.unify(&, $child)}
@content
.wrapper .field
@include unify-parent("input")
/* ... */
@include unify-parent("select")
/* ... */
In general thereʼs a deeper discussion to be had here about how parts of a syntax definition correspond to types in their interpretation.
Steps:
Some weird quirks and anti-quirks Iʼve run into while implementing stuff:
{overflow: auto hidden}
so that it scrolls horizontally but not vertically in the body of the post.
Unfortunately, due to how scroll containers work in CSS, this makes only the horizontal scrolling move the headers, not the vertical scrolling, which is kind of annoying 😒.
I donʼt know what to do about it.border-image
tweening at the moment.
Itʼs a long story why Iʼm using it in the first place (for info boxes), but I like it both with and without.:focus-visible
is actually supported now.
I swear the last time I was doing this stuff I was going to have to implement it myself.<label><input></label>
pattern, to avoid having to generate an id
for the <input>
, but that doesnʼt work when the <input>
needs to control the visibility of elements with its :checked
status.
Nobody else seems to like doing this anyways …{background-image: linear-gradient(transparent, transparent), …}
appear before the actual background image, since iOS does not want to open up a linear-gradient
image.I finally added LilyPond support!
I wrote a Pandoc plugin to take LilyPond source out of the markdown and render it to SVG. Then I style it a little bit. It is pretty simple!
In dark mode, the ruled staff was visually overwhelming, so I added {opacity: 0.75}
to it.
Still need more output formats. And interactivity!!
I would like to make a nice editor for it. Perhaps based on Spontini (CodeMirror).