diff --git a/lib/asciinema_web/controllers/recording_svg.ex b/lib/asciinema_web/controllers/recording_svg.ex
index 612c54dc0..83beb6f6d 100644
--- a/lib/asciinema_web/controllers/recording_svg.ex
+++ b/lib/asciinema_web/controllers/recording_svg.ex
@@ -395,8 +395,9 @@ defmodule AsciinemaWeb.RecordingSVG do
end
@font_size 14
+ @char_width 0.6
@line_height 1.333333
- @cell_width 8.42333333
+ @cell_width @font_size * @char_width
defp x(x), do: x * @cell_width
@@ -407,6 +408,27 @@ defmodule AsciinemaWeb.RecordingSVG do
defp h(h), do: h * @font_size * @line_height
defp font_size, do: @font_size
+ defp char_width, do: @char_width
+
+ defp x_per_grapheme(offset, text) do
+ # NOTE: Elixir's `String.length/1` returns the number of **grapheme
+ # clusters**, not the number of code points. Luckily, that's what we want
+ # here, as SVG's concept of a "glyph" is closer to the concept of a
+ # grapheme cluster than it is to a code point (glyph is identical to
+ # grapheme cluster as long as the font doesn't have ligatures).
+
+ # If we ever need to support fonts that _do_ use ligatures (such as a
+ # version of Fira Code with ligatures enabled), those will need special
+ # handling. At time of writing, the version of Fira Code used is in TTF
+ # format, so ligatures are not supported.
+
+ # We also manually disable ligatures in the SVG's `
<%= html_escape(text) %>