@ippsketch has a most delightful generative series called 'bent'. There are parallel lines moving up the canvas that sometimes bend to the left or right. Generously, Jeff includes a nice explainer about how they are constructed, and with the "live" links at you can walk through each step of the process. I decided to see what I could do in this area.

The gist of the process is explained as follows: The lines are laid out on a triangular isohedral grid. Some of the triangles in the grid are themselves subdivided; some are erased. Then lines are drawn along the grid. Some of them are 'bent'; these ones are shaded. Then everything is coloured.

My approach, or at least how I think about it, is a little different: this is a species of Truchet tiling where the pattern on the tiles is very simple and the placement is highly constrained. Each of the triangular tiles below has a pattern of three quadrangles forming lines crossing from the lower edge of the triangle to the upper. The lines are arranged symmetrically about the center line. For subdivided triangles the outer lines are dropped. If there are more than two levels of scaling, the largest triangles can have more than one outer band. The symmetry ensures that the outer bands can connect from tile to tile to create a sense of a continuous line. A "bend" is just a rotation of the pattern.

The trick then, is to ensure that the orientation of the design within the tiles is such that things line up.

The first thing to understand is that there are, in this isohedral tiling, two kinds of triangles, coloured here in grey and white: the left pointing triangles and the right pointing triangles.

I am using my XQuery port[1] of Craig Kaplan's Tactile.js to produce the tiling, so I'll follow that terminology: the triangles have two different aspects. If we were to imagine colouring a tiling to produce a nice alternating pattern (as the background tiling shows), tiles with a different aspect get a different colouring. The way the tiling library works, it so happens that drawing the line between edges 1 and 3 will produce the appropriate orientation, regardless. A bent tile will draw line between edges 1 and 2 or between edges 3 and 2, depending on whether the bend is to the left or the right. The aspect ensures that the starting edge is appropriate in either case (starting at the left-pointing apex or the right-pointing apex and continuing counter clockwise). So really, aspect 1 triangles draw the line from edge 1 to 3 and aspect 2 triangles draw it from 3 to 1.

Subdivisions is where things start to get a bit tricky: it is easy enough to subdivide a triangle into four triangles with half-size edges by connecting the midpoints of each edge. The tricky part is to ensure than we calculate the starting edges (i.e. aspects) correctly.

When we subdivide a triangle in this way, the outer triangles will have the aspect of the parent triangle, while the inner triangle will have the opposite aspect. Here that matters mainly in that we must start the triangle at the appropriate point so that edge numbering is correct.

The final component here is the colouring: bent tiles get a different colouration from the straight tiles to produce a nice 3D-ish effect.

But Wait! There's More!

The thing is, there is a lot more to isohedral tiling than just this particular arrangement of straight-edged triangles.

  1. There are different ways of arranging the triangles. Here are a few:

  2. Edge parameters can be varied (this causes the basic shapes to be skewed in various ways). For example:

  3. Edges don't have to be straight. For certain arrangements, edges can follow weaker symmetries or none at all and still fit together. For example:

  4. There are quadrilateral, pentagonal, and hexagonal tilings (in several varieties) also. Here are a few:

The question then becomes: can we apply the same algorithm to these other tiling varieties? How well does it turn out?

Different Edge Parameters and Edge Shapes

As long as we determine where the end points of the lines attach based on edge fractions (e.g. 1/4 of the way along the edge, 3/4 of the way along the edge) and maintain symmetry, the lines will match up just fine. The edge parameters may change the relative length of certain of the edges, but they remain straight, so determining the locations is trivial.

The Tactile library categorizes edges into four types: I (straight, symmetric through both reflection and rotation), U (symmetric through reflection), S (symmetric through 180° rotation), and J (unconstrained).

For different edge shapes, I confine myself to a single quadratic or cubic bézier edge. Points on these curves can be computed in a parametric way, for t running from 0 (start of curve) to 1 (end of curve):

          B(t)=(1-t)²P0 + 2(1-t)tP1 + t²P2
          B(t)=(1-t)³P0 + 3(1-t)²tP1 + 3(1-t)t²P2 + t³P3

Strictly speaking, this will not give divisions of equal length (e.g. t=0.1 may be further from t=0 than t=0.2), so there is a certain amount of wobble introduced into the widths of the lines, but it looks pretty nice for all that:

However, J edges don't necessarily abut completely with their adjacent tile, leaving gaps. The patterns can still be nice, but you lose the continuous line:

Different Tilings

Not all tilings are particularly amenable to the pleasing straight-line effect at all. In some of them the lines need to be tilted at an angle. It is tricky to get the aspect-calculations correct for every case. I am fairly certain I have not done it right in all cases.

The other complication is how to perform subdivisions. For triangles we can always follow the midpoint procedure, and the "opposite" aspect is easy enough to determine. What about for the other shapes? For squares, I divide into squares with half-length edges by chopping each side in two, although it is not always obvious what the aspects of the subsquares should be. In a two-aspect tiling, the subsquares away from the diagonal from the start edge get the other aspect, but in a six-aspect tiling? Unclear. Pentagons and hexagons are even trickier because we can't simply tile a pentagon with half-size pentagons or a hexagon with hexagons, we must switch to a different shape, and aspect calculations are even less obvious. Again, I'm sure I am not doing this right in every case, and the subdivisions do not usually look that good with these shapes. Be that as it may, we can either cut a pentagon into a quadrangle plus a triangle or into three triangles. Crucially, these parts are actually at the same scale as the parent pentagon because we don't cut any edges. Similarly, a hexagon can be cut into two same-scale quadrangles by drawing a line from one vertex to its opposite, or into six triangles by joining all the opposite vertices. Squares can also be cut into triangles across the diagonal.

I still have work to do when it comes to subdivisions, for sure.

Lines Running Aslant

Certain tilings require the lines to run at a different angle than straight up and down the page. A lot of the quadrangle tilings behave this way.

No Straight Lines

Some tilings just are not amenable to continuous straight lines at all. But here we can get interesting weavings nevertheless.


Hexagonal and pentagonal tilings often produce little knots where the hexagon was subdivided, because of the discontinuity in shapes.


I randomize both the relative thicknesses of the lines and the scale of the tiling. At small scales certain kinds of tilings take on a textural quality. The relative sizing of the lines can give a different feel.


Randomizing the colouring can produce some interesting surprises. I have a collection of colour gradients, and I take colours from a randomly chosen one them, where the colouring for the bent tiles comes from the darker half of the gradient, and the colouring for straight tiles comes from the lighter half of the gradient. The central lines come from the lighter half of the corresponding half. Sometimes this means that the lines are black or very dark and don't show up against the background. Some of the gradients are randomized or have internal discontinuities than can create interesting or unfortunate results.


[1] My XQuery code libraries, including the port/refactoring of tactile.js.