Using KnitML, Part One: Creating the Pattern 
With the upcoming release of KnitML Core Tools 0.5.0 (and the editor that goes with it), I wanted to show you how I approached converting an existing pattern, the Banff sweater designed by Jenna Wilson, to a KnitML pattern.

First, I created a project named Banff.

Then I created the KEL file...

...renaming the default file name to banff.kel.

Here is what I started with. This is a template that highlights the basic structure of the document.

A KnitML pattern consists of exactly one Pattern element. The Pattern element itself has a GeneralInformation, a Supplies, and a Directions element, and those in turn have elements. If an element cannot be defined all on one line, its contents are indicated by curly braces.

Then I took a look at the original pattern and put that information manually into this document. Since the pattern is given in two sizes, I picked the S-M size to convert.

Elements like Name, Description, and Dimensions were fairly self-explanatory. I converted the square gauge (14 sts x 21 rows = 4 in) into decimal form (3.5 stitchesPerInch, 5.25 rowsPerInch). Knitters who like to read square gauge have an option to create their pattern that way, so I didn't need to worry about that.

For sake of clarity and convention, items surrounded by double quotes are different from items with single quotes. Double quotes refer to literal text or a label. That is, they are written in a particular language (English in this case, as specified by the "en" value by the Pattern element). The values for Name and Description, for instance, are surrounded by double quotes.

Single quotes refer to system IDs. These IDs provide a way to refer to the element upon where they appear in a different part of the pattern. It's a good idea to make them readable, but they don't have to be (they could be generated, for instance). IDs have a few restrictions. They must be unique in the pattern, and they cannot start with a number or cannot contain spaces. (They follow the NCName rules for XML IDs, if that means anything to you.) Additionally, an element cannot refer to an ID that is defined later in the document (elements are processed from the start of the file to the end). That is why they appear with dashes where spaces would normally be ('yarn-type1' or 'needle1', not 'yarn type 1' or '1st-needle').

The original pattern has a section called Patterns. It defines three sets of instructions for use in the pattern directions. The 2x2 Rib pattern is a two-row instruction. RS Decrease Row and WS Decrease Row never appear apart, so I consolidated them into an instruction called Decrease Rows. Also, since the pattern needs to refer to Stockinette Stitch, I included that definition as well. To make these three instructions appear in the header, they went into the Directives and InstructionDefinitions elements, which appears directly under the Pattern element.

Notice that Row elements do not have to have row numbers; they are optional. When they appear in the header like this, if they are not provided, it is assumed that each instruction starts with row 1. (When they are in the body, row numbers will start with row 1 and continue upwards until they are reset.) Additionally, instructions in the header must specify how they are to be worked: flat or round.

Next come the directions themselves. The original pattern is organized into major sections: Back, Right Shoulder, Left Shoulder, Front, Left Shoulder, Right Shoulder, Sleeves (2), and Finishing. In KnitML, each of these sections correspond to an InstructionGroup element. Each InstructionGroup gets an ID (to refer to) and a label (to display).

An InstructionGroup element can be made up of Section elements. Each Section element corresponds to a paragraph in the original pattern. I did my best to make these correspond to the way the pattern was organized.

Here is the InstructionGroup for the back:

I consolidated a few things in this InstructionGroup. The original pattern has the 2x2 ribbing repeat listed as a 42-row repeat. To me, it seemed like the designer meant the ribbing to be repeated for 8 inches, since the row gauge was specified at 21 rows to the inch. I chose to express it by length because it seemed a bit more natural (and possibly more accurate in case a knitter was not getting the exact row gauge). I interpreted increasing 4 stitches "more or less evenly" across 86 stitches to mean k21, m1, k22, m1, k21, m1, k22, m1. (In the future, there may be a way to express an even increase like this, but right now the designer has to be explicit.)

An InformationalMessage element provides a way for the designer to add helpful advice to the pattern. This can be anything from a detailed explanation of a technique to informal suggestions about altering the pattern. Additionally, there will be a way for an InformationalMessage to provide a "summary" explanation of more detailed knitting. In this case, the designer will provide the summary and then the details of the technique, and the knitter can choose to "fold up" the details if they don't want to see them (or the pattern can start "folded up" if they prefer it that way).

Notice how some parts of the pattern have a "State sts" element, while others say "State 34 sts." I did this mostly to show both ways of doing this. "State sts" will simply state the number of stitches currently being worked (whatever that number is). "State 34 sts" will do the same, but it will ensure that there are 34 stitches being worked and throw an error if it's not. This can help identify copy and paste errors.

The next section is the back right shoulder.

This section highlighted some deficiencies in the current KnitML specification. For instance, there is not yet a way to express putting stitches on a holder in KnitML. (This will change in an upcoming version of the specification.) As a result, there is an abnormal bind off / cast on combination in this InstructionGroup that doesn't quite follow the original pattern. Please forgive this section for now. :)

I then went on to transcribe the Left Shoulder (Back), Front, Left Shoulder (Front), Right Shoulder, and Sleeves. The Sleeves required a level of detail which was merely summarized in the original pattern. Since KnitML needs to know exactly how to work the stitches, I had to derive the details based on the general instruction. (This will be implemented as a foldable instruction in the future.)

Here is how I generally approached transcribing each row from the original pattern. I started out copying each row from the web site and pasting in into the KEL file. Then I did some minimal altering to make it fit into the KEL format. For example, the original pattern had a purl 1 through back loop expressed as 'p1tbl.' In KEL this is actually 'p1 tbl' (with a space). [RS] / [WS] also look like 'rightSide' and 'wrongSide' instead. Also, the desinger used spaces to delineate her row labels, whereas KEL expects colons. (At some point, some of this expected formatting may be able to be customized by the designer. We're not there yet, though.)

Each row takes the form of:
Row [number(s)] ("rightSide" | "wrongSide"): operation(s)
Row [number(s)] ("rightSide" | "wrongSide") {
For instance:
Row 1: k to end
Row 2 wrongSide: p to end
Row [3,5,7]: k to 2 before end, p2
Row [4,6,8] wrongSide {
p to 2 before end
If you don't want the row number to appear, use the NextRow element instead. If you have a short row, use ShortRow.

If you specify multiple row numbers that are not sequential (such as Row [4,6,8] above), you must surround the complete set of rows with an Instruction element. So the above rows would actually look like this:
Instruction 'inst1' {
Row 1: k to end
Row 2 wrongSide: p to end
Row [3,5,7]: k to 2 before end, p2
Row [4,6,8] wrongSide {
p to 2 before end
The last InstructionGroup was the finishing instructions. The KnitML Specification currently doesn't have a good way to express picking up along an edge, so this section is done as InformationalMessages surrounded by Sections. Defining edges will be in a future spec.

That is how I created the pattern. In the next post, I'll show you what I'm able to do with the pattern once it's in this format.

[ 1 comment ] ( 34 views )   |  [ 0 trackbacks ]   |  permalink
Why an Expression Language is Important to Get Right 
I heard Martin Fowler give a talk a few weeks back about domain-specific languages (DSLs) and their role in software development of the future. He validated a lot of the assumptions I have been making along the way with the Knitting Expression Language (a DSL for knitting patterns), so it certainly feels good to know that I'm on the right track.

One of the most interesting points he made about DSLs was that they can enable people who don't think of themselves as programmers to program. His example was Cascading Style Sheets (CSS). Web designers don't usually consider themselves to be programmers, but they are usually proficient in writing style sheets. Since CSS is a language that is targeted for a very specific purpose (describing presentation of HTML pages), it doesn't "feel" like a programming language. Yet that's what it is. It's not a turing-complete language, but that's one of its strengths.

DSLs, in fact, aren't limited to computer languages; they can be relevant to language in general. Martin's example of this was the jargon required to order your favorite, multi-adjective drink from Starbucks. A Grande, Non-Fat, Vanilla, Decaf Frappuccino with Whip doesn't have much meaning outside of Starbucks, yet it is a concise way to communicate your specific drink preference to the barista. (By the way, this is not my favorite Starbucks

It should come as no surprise, then, that directions for any knitting pattern use terminology from an informal DSL. There are relatively standard abbreviations for knit, purl, slip, etc. Even though a legend is usually provided with the pattern, most knitters do not need to refer to it to understand that, for instance, k2tog
means "knit the next two stitches together through their leading loops, creating one stitch out of two." We have to keep this in mind when creating a computer-based DSL for knitting patterns. Since there is already a DSL for expressing patterns, we should make our DSL look as much like the existing one as possible.

I've run across several knitting applications that claim to have "pattern-like" syntax, but in reality its expression is significantly hampered by the underlying programming language. This from the
Knitter project, for instance, still feels very much like a programming language:

sk fix(-3,0,0) co 7 fix(3,0,0)
turn k 8
turn k 2 k2tog k 2
turn toEndk

It would be fairly unreasonable to expect designers to express their patterns in this format.

This knitting chart generator has much clearer syntax, yet the square brackets around many instructions make this a bit awkward:


The tool makes this somewhat easier to deal with by providing a graphics for create the chart. However, point-and-click solutions are traditionally not very fast. What if I were transcribing row-by-row instructions out of a book? In that case I can use type in the syntax, but now I'm hampered by the square brackets. What if the pattern were published on a web site? I would want to copy/paste the directions, but short of coming up with a fancy regular expression, I would have to do this by hand.

Now, I'm not meaning to knock the work of the Knitter or Orangellous folks. They've done a lot of work to create their software, and I'm sure their programs will provide (or already have provided) value to the knitting community. And, to be fair, the usability of their syntax was not top priority. However, they may want to consider that an awkward syntax has the potential to get in the way of adoption.

You may be wondering how close you can get to the look and feel of a real pattern while still writing something that a computer can understand. If you've been reading this blog, you can probably guess. :)

You could write the above directions like this in the KnitML Expression Language (KEL):

co 8 sts
Row 1: k8
Row 2: k2, k2tog twice, k2
Row 3: k to end

This is indistinguishable from a real pattern. Yes, there is a bit of syntactic baggage to set up the pattern, and I need to take a closer look at improving some of it. In the interest of full disclosure, the full pattern would look like this:

Pattern {
Directions {
co 8 sts
Row 1: k8
Row 2: k2, k2tog twice, k2
Row 3: k to end

It's also worth nothing that KEL patterns are not KnitML patterns, per se. Rather, they translate into KnitML patterns. KnitML is an application of XML, which represents a knitting pattern's canonical form. A canonical form is very important as an interchange format between software components, because the software processing is greatly simplified. Having a DSL sit on top of the canonical form gives us the best of both worlds. We get pattern readability up front, while programmers don't have to write software for every conceivable expression difference.

To put it another way, KEL allows you to write patterns in a familiar way. In turn, it translates that into an internal standard that software of all kinds will rally around. Then any knitter can render the KnitML pattern in a form that's most familiar to the way they read patterns. Computer DSLs don't have to be syntactically perfect for them to be usable, but they should be clear enough to be meaningful and easy to use. The more meaning their syntax conveys, the less intimidating they will seem to the average user. Programmers can keep "computery" languages to themselves.

KnitML 0.5.0M3 available 
This is a milestone release only, which means there is a little ways to go before everything is ready for 0.5.0 final. However, I'm pretty confident that the "big" things for this release are in place. Please select the Milestone Releases link from the side menu to download the latest.

The charting software is getting fairly capable. The patterns can now be rendered in HTML format, which means that the software can take advantage of some of the more popular free symbol fonts available.

Take a look at Nutkin2 rendered in four different styles. The KSW and Aire River versions require download and installation of the Knitter's Symbols Font and Knitting Font 2.00, respectively.

Admittedly I haven't tried out the no-stitch elements yet, and I'm pretty certain that something will render strangely if there are rows with unevenly-balanced increases and decreases.

By the way, if you are getting excited by all of this and want to lend a hand, just let me know. I would like to expand on the user's guide and design guidelines document on the wiki.

[ 2 comments ] ( 14 views )   |  [ 0 trackbacks ]   |  permalink
Charts are Coming in 0.5! 
Probably the most exciting feature of the 0.5 release is the ability to produce charts from KnitML patterns. Here is a picture of the Nutkin2 pattern in chart form:

What you see here is the pattern produced in HTML format using a locally-installed knitting font (specifically the Knitter's Magazine font by David Xenakis). Some of the formatting is a bit rough around the edges, but the final form will look nicer.

If you don't like the Knitter's Magazine font, you can easily plug in a different implementation of the chart writer that uses a different font (such as Aire River). You can also use a fixed-width font and text art laid out on a grid. (See the text art form of Nutkin2.)

As a knitter, you will be able to apply your own favorite symbols for knitting maneuvers instead of the defaults. You will be able to choose which instructions get charted and which become written instructions. As a designer, you can make your chart look exactly the way you intended it to look by providing a set of images that will correspond exactly to each instruction. (Design software such as Knit Visualizer could make this quite easy to do.)

Don't like charts at all? You can simply set an option to always produce written directions, even if the pattern was originally designed from a chart.

Nutkin Two, of course, is a very basic (almost simplistic) example of a chart. Charts can (and often do) get much more complex. However, I'm quite optimistic that, while there will be challenges along the way, most designs conceived as charts will be able to be represented in KnitML and still be able to be interpreted as charts.

Fixed version for Mac OS X 10.5 
If you are running OS X 10.5 and were having trouble getting GPEC to work, try GPEC 0.1.1a. The short answer is that 10.5 runs Java 6, but Mac's Java JVM only runs 64-bit programs, and some underlying code in Eclipse still needs to run some 32- bit software. Since Mac comes with Java 5 as well, 0.1.1a simply uses Java 5 instead of the default version from the operating system.

This should all work in theory. Being that I don't own a Mac, please advise me if I need to try again.

