However, since Adobes prices have absolutely skyrocketed, I have recently switched to using Affinty and thus can no longer use that method.
Because even though I am generally very happy with Affinity, the Distort & Transform > Transform effect is not available in Affinity.
There are ways to duplicate elements that produce the same kind of result, but if you want to adjust the grid, you can’t just adjust it in 4 places like with the Illustrator method. You basically have to start from scratch.
I learned that last December, when I wanted to quickly throw a grid together in a different x-Height than I usually use for a notebook and realized it’s a pain in the ass.
There’s this rule in programming, that when you find yourself repeating the same kind of code, you should turn it into a function.
So, that’s what I decided to do.
And that’s how I fell into the rabbit hole of drawing grids with code.
The least restrictive and least helpful for calligraphy is the Dot Grid. It is great for Hand Lettering, but not so much for Calligraphy, since it does not even offer proper straight lines. It is great if you want to draw boxes on it, though.
The Graph Grid is probably the most common grid you’ll find pre-printed on paper. It will work fine if you are dealing with upright letters and use consistent ratios. But it’s not very helpful for slanted scripts.
This Area grid, is something I’d often create for myself, when I wanted to have flexibility of how big I wanted to write. I really like this type of grid, because It just features slant lines and lines with a pre-defined x-height and then you can space your letters how you please.
This is what I consider a proper calligraphy practice grid. It has a predefined x-height and ratio. It features slant lines to help with the angle of the letters and a small indicator where the baseline is and the x-height. This is the type of grid I’d offer in my workshops and teach on.
A question you might be wondering if you aren’t a coder is how would you even draw with just code. Aren’t images always made with graphical interfaces? No, actually, there is an image format, that follows quite the semantics.
SVG stands for Scalable Vector Graphics and it is a format that is used to define vector-based graphics for the Web, it is a format that Illustrator and Affinity and all other vector programs can export to, but it is also a format that features quite semantic tags that can be read and understood by humans. (At least some of them, the path tag is a bit of a mess to understand.)
Well, I guess if you were a masochist you could actually do all of the math manually, but since i wanted to end up with something generative, JavaScript became necessary.
And as someone, who always says that I am only decent at math as soon as letters are part of it, SVG Code is so much easier to understand when you are doing the math with variables instead of numbers.
It is fascinating, how much more complicated a task becomes, when it has to be solved on an abstract level, instead of just having to work with given parameters.
Drawing a grid with a ruler and a pencil, takes a few seconds. Doing it in illustrator mere minutes.
Doing this in a generic manner that allows you to adjust literally everything is a different kind of task, that took me a few days.
Believe me, I was not prepared to dig out old trigonometry memories and googling math formulas… but it is very fascinating, to dig into what actually happens mathematically, when your goal is a space-efficient, even grid.
Speaking of goals, before diving into a coding project, it’s best to define what the code is supposed to do.
So, here’s what I wanted to achieve with this code.
The code should put out all types of grids I previously mentioned, with the ability to adjust all kinds of parameters.
The resulting SVG should be able to be opened in Affinity and Affinity should render it like a browser (which affected the SVG features I could use).
The end result should be something that I could offer my lettering students so that they could practice with different parameters.
So, this was my first time coding SVG. As a professional frontend engineer I have worked with a lot of SVG. It usually consists of cleaning them up, optimizing colors, making them responsive-capable and bundling them up to be used as Icons on a website.
But this was different. I was writing SVG.
There were a lot of questions in my head, but I had seen people do it before, so I was just going to start.
calligraphy Grids consist of lines and boxes and luckily, those are the easiest part of SVG.
SVGs are just a setup of a coordinate system. So in the container you define the size of your canvas and establish abstract units, which you then use to position your elements.
So, in my early tests, I started by setting up SVGs that had square canvases and then did a bit of math to figure out my coordinates.
Horizontal and Vertical Lines were also pretty straightforward.
<line> elements are made up of two points with x and y coordinates each.
To make horizontal lines, both y coordinates are the same and to make vertical lines, both x coordinates are the same.
So, if I want to draw a horizontal and a vertical line through the canvas, I need to know my middle point first.
So, then I can figure out my line coordinates. I like to think of it like this:
If I were to drop a line, horizontally, I’d first figure out my point on the y-axis, this is my “grid position” and then I’d figure out where my line starts on the left and where it ends on the right.
For the vertical line, I’d do the same, but the x-axis is my grid position and then I think top to bottom.
I find that easiest to visualize.
So if I wanted to draw a horizontal and a vertical line through the center, I’d do it like this:
When it came to drawing dashed lines, my original idea was to use circles, but then I realized that that will create a lot of elements, so I decided to use dashed lines instead, which use
I did still end up going with circles for the dot Grid in the end.
Circles work a bit differently than rectangles, because they are drawn from the center and instead of a width and height they have a radius.
There are different methods of making slanted lines in SVG, but the one I found most intuitive was to use the transform attribute.
In Calligraphy, our slant lines are always relative to a horizontal line, so my initial thought was to just start with a horizontal line and then rotate it. In code, we rotate clockwise, so a positive number rotates the line to the right and since we want to rotate it to the left, we use a negative number. We’ll also need to specify a point to rotate around, so we’ll use the middle of our line.
Obviously, my angle had to be 55, because Calligraphy.
Show SVG Code
The way we draw slant lines in our classic calligraphy line though, ended up not being rotated with transform, but using some trigonometry.
But this was a problem for later.
I had gathered all of my information and was ready to get into my coding project.
I decided to write a collection of Typescript Classes that would help me generate the SVGs. First, I’d write a class that would set up the entire document and some shared functionality and then I’d write a subclass for each type of grid.
I went with Typescript because I wanted to be able to use Interfaces for the configuration Objects and to just make it a bit more structured.
I wanted my grids to be placed on a traditional paper size and have a document title that mentioned the grid type and some of the useful parameters like the x-height, slant angle, ratio etc, depending on each type.
And then I’d also like a box around the grid with some rounded corners for that classic look.
I started with my classic graph grid.
Which was done fairly quickly, it was just throwing a bunch of horizontal and vertical lines onto the canvas by taking my cell-Size and my drawing area into account.
Let’s do a quick interlude here from a future version of me, who had written this entire thing and was planning to refactor the website part of this.
But then I had a conversation with a coworker, who is a lot more experienced with SVG than I am and he told me about the pattern tag.
So, as soon as I heard about that, I set out, to make my code more efficient and cool and was planning to rewrite the entire thing.
I prototyped it with Dot and Graph Grids and it was soo cool.
pattern allows you to define a pattern that can be used to fill a shape. So, I could just define my lines once and then use them to fill my entire drawing area.
Dot Grid is even cooler. We can just take one line with a dashed line that’s made to look like dots and repeat that.
Show SVG Code
However, that was already at a point where I had learned that in Affinity <mask> does not work, while <clipPath> does. And I had to adjust my code accordingly, so everything coming out beyond the rounded corners of my area got cut off.
So, I was cautious to not get too excited about this, and make every grid before testing.
And this is where I stopped and saved my svg and then opened it in Affinity.
Yeah, one big nothing.
Well, I guess in the end, it is good I didn’t create everything with pattern because then I’d have to rewrite it all.
Because now I just knew to save myself the effort. Because the solution I had was working.
I won’t be sharing the entire code here. It’s open-source and you can dive deep into it there.
Generally, in my classes there are two drawing functions makeSVG() and makeSVGString()
And then each subclass hooks into that and adds its specific grid.
There are then helper functions to create groups (<g> tags that make it easier to have similar elements in one place) and to add lines. There was also some masking involved for the rounded area box.
I also have a function that formats coordinates, because more than two floating points make the SVG file bigger and usually the result will be exact enough with two.
You’ll see addSolidLine and addDashedLine functions in the code, but they are just wrappers around addLine that make it quicker to read whether it’s a horizontal or vertical line and if it’s solid or dashed.
The Dot grid is setup similarly, but here, we’re not drawing lines in the loops, but instead, we’re adding x and y coordinates into arrays, which then gives us the coordinates of where the horizontal and vertical lines intersect. This is where we then draw the dots using circle elements.
Okay, let’s go back to the slant lines and the problems with rotations I mentioned.
At that point, I had not yet learned that clipPath could solve my issue of mask not working in Affinity and my PDF export. I was living with the issue of lines being outside of my rounded corners, but I could not have slant lines protruding out of my area everywhere.
So, what I usually had was a start point of my line, and then usually the length of the line, as well as the angle of it. So, then I could calculate the end point of the line using trigonometry.
So, the drawSlantLine function is not one that implements a transform, but instead calculates the end point of the line and then draws a line via coordinates.
I also have a few limitations for slant lines right now, with the current methods. So right now, my angle needs to fall below 90 and above 25degrees for optimal results, but I think since we’re in calligraphy world, that is fine.
There is always a graph grid for 90 degrees and I don’t think people write that steep ever, or slanted backwards.
In addition to just having horizontal lines at the x-height distance, I also wanted to have the option to add separator lines for half of the x-height, since I like to reference these in my letters, like t, p, e etc.
And then in the Area Context, I wanted to have one main slant line spanning from the bottom left corner to the top left, and then being able to specify how far apart the slant lines should be, and also how long they should be at minimum, since I felt like having tiny lines all the way to the corners was a waste of space and parameters.
So, first it was drawing horizontal lines and separator lines and then it was about figuring out the slant lines.
We start by drawing the longest line, through the middle, and then adding lines to the left and right of it, at the specified distance. And then we have to jump through extra hoops because I didn’t know about clip Path and had to make sure the lines didn’t go outside of the area, by calculating intersection points with the area and then trimming the lines to those points.
In the end, I am not going to rewrite this and use the mask, because this makes the resulting svg cleaner, so I’m keeping it like this, but I could’ve saved myself a lot of headache, because trigonometry is not my strong suit.
The piece de resistance, my workhorse, my beloved, the Calligraphy Lines grid.
Here, I wanted a few more parameters to be adjustable. Not only the slant angle, but also the x-height and the ratio.
And in the calligraphy line grid, I wanted to draw the slant lines differently, Here I wanted the first line to start at the bottom left corner of the descender line and the last line to end at the top right corner of the ascender line.
So, specifying a gap is not really going to work here, because there might be something over if I’m placing lines between two lines. So instead, I opted to have a value of how many lines are drawn between and then they are evenly spaced.
I also wanted the baseline to be bolder than the others, and the option to add an indicator on the left for the baseline.
When using the area Box, I also wanted to be able to specify a buffer, so that the lines don’t start right at the top and are cut off by the rounded corners. That is very much a stylistic choice though, so it was configurable again.
The main grid is drawn like the graph Grid horizontal lines, and then there is a separate drawing function, to take care of drawing ascender, descender, base line, slant lines and all the other optional lines.