How to Knit Objects Weird

Post Metadata

If you saw my last blog post, you know that I work on design tools for knitting unusual things. Today I’m introducing my new project, which is a design tool to support knitting things in unusual ways. I’m also introducing my new amazing collaborator, Marlena!

So let’s say you’re a knitter (some of you probably are!). If you knit or crochet, you’re likely to know of Ravelry, the foremost gathering ground for knitting patterns on the internet. Well, let’s say you go to download the instructions for Martha Stewart’s cozy mittens, and it has this fun knit-flat detail with an interesting seam.

Diagram showing two mittens side-by-side in various stages of completion. The left mitten is a fully flat knit shape that has not yet been sewn together. It almost resembles the shape you would get if you cut a mitten along the fingertips and thumb and unfolded it, except on one side, the thumb flap is ponting down instead of up. On the right, the mitten has been folded over and the fingertips have been sewn. The thumb flap that was previously facing down has been flipped up so the thumb flaps can be sewn together.
Martha Stewart’s Cozy Mittens: https://www.marthastewart.com/1042286/cozy-mittens

You’re reading through the instructions, but you realize you want to make the thumb longer. And also, you want to knit the cuff after finishing the body of the mitten because you want to use a fancy directional design. Basically, you want to make some changes to the fabrication plan. How can you make these edits and get a new knitting pattern?

A suit-and-tie-wearing man in an infomercial is speaking to the camera.
Has this ever happened to you?

Can we turn to computation? Lots of existing work1234567 compiles some kind of shape specification to a fabrication plan. The thing we noticed, however, is that these tools provide only one or a few fabrication plans, which is entirely determined by the geometry of the input and sometimes a user-supplied thing called a “time-vector field” and a few sliders. So, if I gave you this specification of a mitten, you’d really only be able to knit it in the round from the bottom-up or top-down, or starting at some point like the end of the thumb and progressing outward.

That does not encompass my original knitting plan, which is knit flat rather than in the round, nor my new desired knitting plan, which includes knitting the cuff after the rest of the body.

A sketch of a 3D long-sleeved sweater, coloured with a rainbow gradient that uniformly transitions from top to bottom, starting with red at the top and going to blue at the bottom. The caption reads "(a) Input time function on the garment manifold".
Example taken from Knit Sketching (Kaspar et al), showing a default time vector field

So how would I even go about representing my downloaded pattern as input to a knitting compiler? Maybe a small subset of math experts could painstakingly define their own time-vector fields, but otherwise we can’t get any computational help.

Even given a starting fabrication plan, there isn’t really an easy nor ergonomic way to explore different plans. As plans get more complicated, they require you to manually compute new shapes, keep track of fabrication steps, and avoid violating constraints. What would you do if you wanted to knit part of it in the round, or add colour or texture detail to sub-components, or break the design apart into much smaller pieces?

The fabrication plan is what records details like these, which is why we believe that the design of a sock, or a mitten, or anything else depends directly on the fabrication plan, and not just the shape: if we wanted, we could make socks from vertical stripes of knitting, or wrapped ribbons, or by leaving the heel until later – producing distinctly different designs.

Three different sock designs. On the left, there are two socks juxtaposed, both knit in the same orange, purple, and brown variegated yarn. The first sock is knit with dense stripes of colours. The second sock appears to have large patchwork blocks of each colour instead. In the middle is a sock that made of blue and green yarn, where the stripes of knitting resemble a ribbon wrapped around a foot starting from the toe and going up. On the right is a completed sock and a partially-worked sock, showing that this sock is made by first knitting a tube and then knitting in a heel afterwards. [Left] General Hogbuffer Stripe Tease by MiaMidori: https://www.ravelry.com/projects/MiaMidori/stripe-tease, [Middle] Louise Robert Carousel sock: https://knitty.com/ISSUEss12/PATTcarousel.php, [Right] Afterthought heel: https://vickiehowell.com/afterthought-heel/

Each of these designs represents a totally different way to make a sock, a way that craft knitters have imagined and desired, and yet none of these patterns are well-supported by existing software.

What can we do to specify fabrication plans and integrate them into our knitting compilers? In other words, how can we expand the space of programs we can actually compile to?

I’ve been thinking a lot about this problem. My solution is couched in a couple basic principles.

  1. We need some way to codify fabrication plans as standalone objects, rather than implicitly attaching them to the shape. A way to do that simply is as a text format, which is easily distributed, ingested, and can even be manually understood without too much headache.
  2. 3D representations offer too many degrees of freedom, especially when most objects are actually composed of simple panels that are connected together. To that end, I propose a 2D-only representation, where SVG shapes are used as inputs, and the user can specify how to assemble or disassemble them. 2D shapes are also great because algorithms over 3D shapes can be brittle, especially considering knittability assumptions.

Important design tasks are poorly supported in previous systems: representing the myriad ways knit objects are made, allowing independent changes to the shape or the fabrication method, and encouraging exploration of fabrication plans without painstaking manual editing. Our system will enable them.

For example, if we wanted to design a mitten, we could start with this outline that shows the basic shape of the mitten. We create two of the same panel, and join them together at the sides.

In the foreground is a simple line drawing of the shape of a mitten. This line drawing is duplicated and offset back and to the left, with red lines drawn between corresponding points on the shape to indicate that the edges are connected together.

Now, we can play with this shape. We can cut things up and put them back together in different ways to produce all these different fabrication plans.

The same simple line drawing, with four variants. The first variant is knit "default" with no changes. The second splits the shape between the hand and the thumb, labelling the hand "1" and thumb "2". The third further splits off the fingertips from the palm, with the fingertips labelled "3", the palm labelled "1", and the thumb labelled "2". The last variant has a dotted line along the fingertips, around the thumb and down to the cuff, implying it will be cut along that line to be knit flat. (left) knit top to bottom, (left middle) knit the body first and thumb second, (right middle) further separate the palm, thumb, and fingers, (right) knit flat and sew along dotted line

In this blog post, we’ll break down part of the pipeline we’re writing to make this vision of a new, 2D fabrication plan compiler a reality. In particular, we’ll talk a little about how to compile an SVG shape into a specification for a knitted object, especially when there might be additional knitting complexity.

A Simple Introduction to 2D Panels for Knitting

Knit objects are fundamentally made of loops that are pulled through other loops. This diagram is 3 loops wide and 3 loops tall, and is made of knit stitches on the bottom and purl stitches on the top:

A set of loops. Each loop has a "head" and "legs", such that the yarn starts at the bottom of at the left leg, curves around and goes back down in the head, becoming the right leg and going back up again to form the left leg of the next loop. There are 3 loops in each row and column. The legs of the upper loop and head of the lower loop is arranged such that each set of legs are either arranged on top of or under the head in the row below. The top row has heads over legs, and the row below has legs over heads.

How do humans know how to produce the correct knit objects? When you download a knitting pattern from online, it often looks like this:

A screenshot of a knitting pattern that reads: "Rnd 1: (k14, k2tog, yo) rep to end. Rnd 2: (k13, k2tog, k1, yo), rep to end." and so on until "Rnd 15: (k2tog, k14, yo) rep to end."

which is a series of instructions for the knitter on what new loops to make and where. So, taking our original diagram, the instructions might have looked something like this:

row 1. k3
row 2. p3

But you can imagine that if I wanted to change the width of the rectangle, I would have to make sure to update both the instructions for row 1 and row 2.

Now you might think of course, “parameterize!” So one simple solution would be to automatically derive the knitting instructions based on the shape I want. For example, I could give a width and height of a rectangle, and then generate the correct number of rows and instructions within the rows.

Additionally, if I wanted to change the width of the shape as I’m knitting, I can use an important shaping tool: increases and decreases. An increase creates a loop where there previously was none, and a decrease reduces the width from two stitches to one stitch.

So, to parameterize over more complex shapes, I could give an SVG specification, which I could then discretize into a graph of knits, purls, increases, decreases, and other stitches.

Capturing Complex Fabrication Aspects

Something that is difficult to capture with just a pure specification of the shape outline, is the fact that within a pattern, the knitting direction might change. A pattern might do this to make an interesting design feature or distribute colour in a different way.

A collage of three images. On the left is a sock knit in blue, brown, and yellow stripes. I indicate three direction changes around the heel of the sock. In the middle is a top-down view of a hat, which is made of six curved wedges, similar to a plumeria, in a striped brown-and-tan. I indicate direction changes for each wedge. On the right is a pair of white mittens, visually divided into roughly three triangles by increase/decrease lines. I indicate how the thumb is a different direction from the palm, which is a different direction from the fingertips. [Left] Basic Sock with Integrated Heel made by alohanoa (https://www.ravelry.com/projects/alohanoa/basic-sock-with-integrated-heel), [Middle] Little Venice made by thirdsetofneedles (https://www.ravelry.com/projects/thirdsetofneedles/little-venice), [Right] EZ Garter st mittens made by angharadt (https://www.ravelry.com/projects/angharadt/sideways-mystery-mittens-wg06-so06)

It might even be to achieve a shape that is simple to do with a direction change but difficult without one. Consider a cone net:

A diagram showing first a cone upside down, then the same cone that has been cut from the base to the tip, and then the unfolded version of the cone, which is a subset of a circle along an arc (almost a half-circle).
Source: https://amsi.org.au/teacher_modules/Cones_Pyramids_and_Spheres.html

If we wanted to knit the shape of the net, we could do so by starting from a single stitch (such as the leftmost outer point or the centre point) and increasing and decreasing aggressively at the boundaries to change the width but keeping the middle flat. I’ll illustrate this with a diamond rather than a cone, which has a similar shape of widening and narrowing. Observe how the lines of bumps stay parallel throughout the object.

A knit diamond in multicolour variagation. The diamond is knit from top to bottom, so the rows of stitches are consistent and parallel like lines on a ruled page.
Source: https://homemadeatmyplace.blogspot.com/2013/08/make-it-knitted-diamonds.html

Or we could basically knit triangles side-by-side, joining them with increases and decreases placed in the middle rather than at the edges. Observe here how the lines of bumps changes directions from one half to the other – it’s no longer parallel throughout the object.

A red diamond photographed from an angle. This diamond instead has a line dividing it down the middle, forming two triangle-shaped sides, with the left side's stitches all parallel to each other at a 60 degree angle from horizontal, and the right side's stitches all parallel at a -30 degree angle from horizontal.

This blog post has a great comparison and also shows how the knitting direction affects the overall look.

Here’s an example I knit of a full cone pattern, where you can see the lines of bumps change angles as you go from left to right:

A small pink knit flat piece, about a semicircle in shape. It is divided into five different roughly triangular sections where the stitches are all parallel within the sections, but the angle from horizontal differs between sections. The angle starts at about -70 at the left side, then -30, then 15. 60, and 90 roughly.

These direction changes also do more than change the look of a flat shape – their effects vary from outright creating shapes that don’t lie flat using short rows, to simply encouraging 3D structures by using increases/decreases to create natural fold lines that don’t exist on a homogeneously-knit shape.

So, carefully placing directional changes allows you to control the 3D shape more precisely. Obviously, we need to support this type of instruction so we can fully express different fabrication plans. Specifying direction changes range from very cumbersome to impossible to do in existing compilers.

Now, how do we actually put these direction changes into our SVG specification of the outline, which is essentially just a very lightweight set of points?

One way could be to specify the line where the knitting direction changes. Or alternatively, give the knitting direction for each “point” within the SVG shape. But, you can imagine that these types of specifications involve searching within the knitgraph for the correct places to create direction changes.

We discovered a simple approach that doesn’t require us to search within knitgraphs and edit them at all. First, note the way that the direction changes create intuitive sub-shapes within a flat knit panel.

The same pink cone net as above, but with red triangles denoting the different segments, and arrows describing the knitting direction (perpendicular to the angle of the stitch lines).

Our observation is that direction changes occur naturally when we first create knitgraphs for these sub-shapes, and then merge them together. Essentially, the direction change is caused by a series of increases and decreases placed between sub-shapes. If we were to knit each sub-shape on its own, it would already have decreases along the edges. So, if we just join these sub-shapes while knitting, the direction change happens for free.

That is to say, the direction change is the byproduct of merging these sub-shapes!

Now that I’ve told you about the basic idea behind enabling direction changes, Marlena will walk us through the high-level of how this happens in our tool!

Low-Level Cone Example

Let’s walk through what it looks like to represent two sub-shapes of the cone net above. We’re going to create two triangles and connect them along their side edges.

We begin by defining two SVG triangles. These shapes outline two panels of the cone. We derive knitgraphs in the shape of the outlines in order to merge and manipulate knitting direction.

Two triangles with vertices labeled (0, 0), (9, 0) and (4.5, 5).

Diagram of two knitgraphs. For each knitgraph, loops represented as circular nodes are arranged in a triangle. Horizontal edges connect neighboring loops and vertical arrows connect parents and children.

Each knitgraph represents a panel of knitting with the shape of its SVG counterpart. A knitgraph, similar to a physical piece of knitting, is composed of connected loops. Neighbor loops are knit sequentially on the same segment of yarn, and child loops are pulled through their parents. Our knitgraph diagram represents loops as circles, neighbor relationships as horizontal lines, and parent/child relationships as arrows pointing from parent to child. The knitting direction represents to the order that stitches are knit, where parents come before children. Each knitgraph has a unique ID, which loops store. This identifier maintains organization once single knitgraphs are merged together into compound knitgraphs.

Contrasting pairs of knitgraph diagrams. Top pair show loops pulled through each other, with neighbor strand of loops in green, a parent loop in blue and a child loop in red. Bottom pair shows loops represented as nodes with a neighbor row of loops in green and a blue parent loop below a red child loop.

Knitgraphs are useful because they are characteristic of real-world knit objects. However, they are not user-friendly to interact with. Interaction usually involves manipulation of specific loops which can be difficult to identify among the numerous loops that compose a knitgraph. To prevent users from handling knitgraphs directly, we establish a link between loops and the location they correspond to on the SVG. Thus, users specify a location on the SVG and are returned the loops at that location on the knitgraph. Compound knitgraphs are linked to several SVGs which are distinguishable by the unique IDs of the knitgraphs they are individually linked with.

The next step in our cone construction is to merge the triangle knitgraphs on edges that contain loop decreases. In other words, we will join the knitgraphs by creating neighbor relationships between their loops. We first choose one triangle knitgraph to be oriented on the left side of the merge and the other to be on the right. Let’s refer to these as leftTriangle and rightTriangle. Then we identify the edges on the SVGs that correspond to the knitgraph edges we want to merge on. This will be (9, 0) -> (4.5, 5) on the leftTriangle and (0, 0) -> (4.5, 5) on rightTriangle. A verification process ensures that these edges correspond to an equal number of loops on the rightmost edge of leftTriangle and leftmost edge of rightTriangle.

The two triangle knitgraphs from before, now with dashed lines running between the loops on their edges that will become neighbors. Each row of loops is lined up straight

At this point we know which loops should facilitate the merge and we can assign neighbor relationships to the loops that are aligned next to each other. The result is a compound knitgraph with a knitting direction change. (Note that as a consequence, in our system, we know that non-compound knitgraphs never contain direction changes.)

The new knitgraph resulting from merging the triangle knitgraphs. The triangles have been pulled in to each other at a 45 degree rotation. There is a now a bend in each row of loops.

We complete our cone by repeating this process on the compound knitgraph with a couple more triangle knitgraphs. There will still be one open edge that the user can sew up to complete the closed cone shape.

The knitgraph resulting from merging two more triangles onto our compound knitgraph. The four triangles are arranged in a circular fashion with the last remaining edge still open.

The closed version of the four-triangle knitgraph. This is a view of the final cone knitgraph from the top.

Conclusion

Merges belong to a larger collection of operators over knitgraphs that we have designed to support expressivity and knittability in the 2D system:

  • Gauge: SVGs are unitless – when they are converted into knitgraphs, a user-defined discretization takes place that determines how many loops a specific distance in an SVG corresponds to. If it is too few, detail can be lost from the intended design. We provide gauge operations to identify and report these effects.
  • Merges: Merging operations allow for simplified manipulation of knitting direction and texture. Merges can achieve short rows in addition to increase/decrease patterns. Short row merges involve manipulation of parent/child loop relationships rather than neighbor relationships.
  • Tubing: Tubing operations facilitate knitting in the round – a technique that the 2D approach would otherwise disallow but is necessary to provide users with a full range of expressiveness.
  • Chunking: Chunking operations verify knittability. There exist real-world constraints over what kinds of patterns can be knit in one contiguous piece. By applying these constraints to knitgraphs, we can recognize when a piece is not knittable and split it into knittable chunks. These chunks are knit separately and seamed together to reconstruct the original design.

Those operations cover pretty much everything we need to do in the land of manipulating knitgraphs, but the system is far from complete. We have the ability to take a complete SVG specification with information about knitting direction, texture, etc. and create a corresponding knitted shape.

But how did we generate that SVG in the first place? How do we support the exploration of different shapes from an initial specification, and write that down so we can disseminate the format later? All of this is supported by a reference-aware scheduling language that begins with a basic specification of flat panels; we then write programs over them using scheduling operators that we define, such as cut, sew, and merge. The program can be interpreted (and re-interpreted for different starting shapes) into transformed SVG shapes and then knitgraphs. We then compile knitgraphs into knitting instructions, completing the pipeline. Finally, there will need to be work making a user interface that supports a natural shape-editing and clicking interaction.

Once we have those pieces in place, we’ll have a new compiler and knitting design system for users to easily create, modify, and explore new and existing knitting patterns across a vast, previously unsupported design space. All those tasks that we found hopeless at the beginning of this blog post will be enabled by our techniques! I think the first thing I’ll use it for is to make some cute clothes for my knitted corgi eventually. Maybe some booties? Let us know what you think!

A hand-knit stuffed corgi on a blue couch that's somewhat anthrophomorphic, akin to a teddy bear. It is wearing a lavender pinafore dress, also knitted, with a leaf scallop edge.

Acknowledgements. Thanks to our collaborators Maaz Ahmad and Mackenzie Leake, as well as our advisors, Zachary Tatlock and Adriana Schulz, for all their input on this project!

  1. Vidya Narayanan, Kui Wu, Cem Yuksel, and James McCann. 2019. Visual knitting machine programming. ACM Trans. Graph. 38, 4, Article 63 (August 2019), 13 pages. https://doi.org/10.1145/3306346.3322995 

  2. James McCann, Lea Albaugh, Vidya Narayanan, April Grow, Wojciech Matusik, Jennifer Mankoff, and Jessica Hodgins. 2016. A compiler for 3D machine knitting. ACM Trans. Graph. 35, 4, Article 49 (July 2016), 11 pages. https://doi.org/10.1145/2897824.2925940 

  3. Vidya Narayanan, Kui Wu, Cem Yuksel, and James McCann. 2019. Visual knitting machine programming. ACM Trans. Graph. 38, 4, Article 63 (August 2019), 13 pages. https://doi.org/10.1145/3306346.3322995 

  4. Vidya Narayanan, Kui Wu, Cem Yuksel, and James McCann. 2019. Visual knitting machine programming. ACM Trans. Graph. 38, 4, Article 63 (August 2019), 13 pages. https://doi.org/10.1145/3306346.3322995 

  5. Kui Wu, Hannah Swan, and Cem Yuksel. 2019. Knittable Stitch Meshes. ACM Trans. Graph. 38, 1, Article 10 (February 2019), 13 pages. https://doi.org/10.1145/3292481 

  6. Benjamin Jones, Yuxuan Mei, Haisen Zhao, Taylor Gotfrid, Jennifer Mankoff, and Adriana Schulz. 2021. Computational Design of Knit Templates. ACM Trans. Graph. 41, 2, Article 16 (April 2022), 16 pages. https://doi.org/10.1145/3488006 

  7. Georges Nader, Yu Han Quek, Pei Zhi Chia, Oliver Weeger, and Sai-Kit Yeung. 2021. KnitKit: a flexible system for machine knitting of customizable textiles. ACM Trans. Graph. 40, 4, Article 64 (August 2021), 16 pages. https://doi.org/10.1145/3450626.3459790