This website is a log of my adventures in programming, computer science, and math.
This website is where I share what I’ve learned.
This website is where I express my aesthetic preferences in web design.
- fluff non-technical content
- quacks microposts
- projects code I’ve written
- links content I’ve read
- uses things I use regularly
- listens music I listen to
To contact me, email hello
at kosalab.dev
.
Colophon
Jotdown | for parsing djot |
Tree-sitter | for syntax highlighting |
MiniJinja | for HTML templating |
KaTeX | for math typesetting |
QuickJS | to run KaTeX in-process |
Fonts
Five different fonts are used on-and-off throughout the whole site.
Let me explain.
The body text uses the increasingly popular and ostensibly overused Inter. Specifically, I’m using version ≥4.0 of Inter, which not only provides a variable font but also ⭐ true italics ⭐. I love how clean it makes websites look, although I do have a few items on my wishlist (namely proper old style numerals and small caps support).
The vintage personality that Bricolage Grotesque brings to display text wonderfully contrasts the modern look and feel of Inter. Another free and open source font, it lacks true italics or other fancy OpenType features, but as a font for headings it is Good Enough™.
Iosevka is my preferred monospace font
.
Although I am blessed with n > 1 monitors today, I still greatly appreciate the 0.5em wide glyphs allowing me to fit more columns within the width of my terminal.
I do not use nor like programming ligatures, so I have those turned off.
To save on bandwidth, I chose not to use italics or obliques, and restrict font weight to the default 400.
The remaining two fonts are actually variants of the same font — Source Hans Sans. The variants are for Chinese and Japanese glyphs respectively, which are both used on the site. Due to Han Unification [1], I have to separately specify whether my bones are 骨 or 骨, which is only mildly annoying in practice. I do subset font files to reduce bandwidth [2], but the extra HTTP requests are unavoidable.
-
A good rundown of the problem can be found at Your Code Displays Japanese Wrong, which is how I first became aware of the problem.
-
Uncompressed, each variant of Source Hans Sans in the
woff2
format is ≈14MB in size. That’s way over my threshold for page weight, and what motivated me to really look into automatic font-subsetting for my site.
Semantic HTML
The HTML generated from the djot that I write should be as semantic as possible. For example, quotations are wrapped in <figure>
elements the citation in a <figcaption>
.
The reason that the rich were so rich, Vimes reasoned, was because they managed to spend less money. Take boots, for example.
…
A really good pair of leather boots cost fifty dollars. But an affordable pair of boots, which were sort of OK for a season or two and then leaked like hell when the cardboard gave out, cost about ten dollars.
…
But the thing was that good boots lasted for years and years. A man who could afford fifty dollars had a pair of boots that’d still be keeping his feet dry in ten years’ time, while a poor man who could only afford cheap boots would have spent a hundred dollars on boots in the same time and would still have wet feet.
Some posts make heavy use of , which is rendered into HTML for aesthetics and MathML for accessibility. The rendering is done entirely at static site generation time [3]. This increases page size but avoids the need for client-side rendering, which is an acceptable tradeoff to me.
-
I would like to not use any Javascript libraries, but AFAIK the only viable options for quality and accessibility today are MathJax and KaTeX. Thankfully, I can embed QuickJS into my site generator, then use it to run
katex.min.js
, passing any found math torenderToString
.
The probability density function for a Gaussian distribution with mean and variance is
Similarly, code blocks are highlighted at “compile time” and converted into HTML:
- testing.py
"""
Deletes the final line in a file.
Modified from https://stackoverflow.com/a/10289740/11457597
"""
import os
with open("path/to/file", "rb+", encoding="UTF-8") as file:
file.seek(0, os.SEEK_END)
pos = file.tell() - 1
# Search for newline from the end
while pos > 0 and file.read(1) != "\n":
pos -= 1
file.seek(pos, os.SEEK_SET)
if pos > 0:
file.seek(pos, os.SEEK_SET)
file.truncate()
For more information about code blocks on this site, please see Overengineered HTML Codeblocks.
Design
The design of this website should be cohesive to the best of my ability.
Regular links are colored blue and visited links are colored purple because you’ve read them and red plus blue makes purple. Links are underlined on hover. Special interactables are green on hover and all interactables show a red outline on keyboard focus.
Where applicable, highlighted text should have a yellow to magenta gradient .
Color
Speaking of color, the website supports both a light and a dark theme. By default, the site will use a theme dependent on the browser/operating system preference. Here is the color palette used on the site:
- gray
- red
- orange
- yellow
- green
- cyan
- blue
- purple
- magenta
Raw HTML
Regular HTML elements can be written in djot
and embedded into the page.
Congratulations for making it to the end of the page!
Here’s a playable sliding puzzle as a reward:
- Moves: 0
- State: Idle
- Grid size: