Knitout (.k) is a file format that can represent low-level knitting machine instructions in a machine-independent way. The format is easy to read and write from code, and reasonably human-readable. It is hoped that knitout can serve as an output file format for design tools, and an input file format for knitting machines and simulators.
Knitout has no relation to the custom sock vendor of the same name.
The remainder of this document describes the format itself, the design principles behind the format, and ends with some comments about particular decisions.
Please do not hesitate to get in touch with ideas, comments, or improvements for the specification. Without your input, knitout cannot grow into a useful specification.
To provide feedback, use the Issues page. You may also contact the authors directly using the email@example.com e-mail alias.
Knitout is a straightforward list of knitting instructions to execute to create a knit object, along with a header describing specific information about the machine it is designed to run on.
Knitout files are named with the
Knitout files contain UTF8-encoded text.
Knitout is line-oriented, and knitout files use the LF character to terminate lines (
Programs that write knitout format files should name then with a
encode them as UTF8,
use only the "space" (U+0020) and "tab" (U+0009) characters for whitespace,
and use the LF character (U+000A) as a line ending.
Programs that read knitout files should support files produced in this way, and may support other extensions, encodings, whitespace characters, and line endings (though they should warn that the file is not standard).
Knitout files begin with a magic string
;!knitout-VERSION followed by a linefeed.
VERSION is an integer indicating the current version.
The version number will be incremented when features are moved from extensions into the main language.
Programs that write knitout should always use the latest version of which they are aware. Programs that read knitout must accept any version number, but should warn if the version is later than one they support.
;;Machine: SWG091N2 ;;Gauge: 15 ;;Yarn-5: 50-50 Rust ;;Carriers: 1 2 3 4 5 6 7 8 9 10 ;;Position: Right
After the magic string, knitout files contain a series of special comments (starting with
;;) known as the "comment header."
These comments give additional information about the machine intended to execute the knitout code in the file.
Each line in the comment header begins with the string "
;;", followed by the header name, followed by the string "
: ", followed by the header value.
The following headers are required because their values influence the topology of the finished knit item:
|Carriers||C1 C2 C3 ...||space-separated list of carrier names; carriers are given in front-to-back order. Note that these names can be any string; knitout backends are expected to map these strings to machine carriers.|
Tools that write knitout must include a
tools that read knitout must warn if a
Carriers header is missing, though they may also continue to process the file.
The following headers are optional:
|Machine||M||the model name M of the target machine|
|Gauge||G||the gauge G (in needles/inch) of the target machine|
|Yarn-C||type color||yarn to load in carrier C|
|Position||P||where to place the operations on the needle bed; Left, Center, Right, and Keep are standard values|
knit + f14 A B ;knit together knit + f15 A B knit + f16 A B ;note to self: maybe put in a tuck here? knit + f17 A knit + f18 A knit + f19 A
After the comment header, all lines in the file contain an (optional) operation followed by an (optional) comment. The operation is everything up to the first ';' character, the comment is everything after:
knit + f14 A B ;knit together ^--operation--^ ^--comment--^ knit + f14 A B ^--operation-^ (no comment) ;note to self ^-comment--^ (no operation)
The operation is a whitespace-separated list of tokens. Leading and trailing whitespace may appear and is ignored. The first token is the opcode, and the remaining tokens [if any] are the parameters.
|in||CS||Indicate that the given carrier set should be brought into action from the yarn grippers when next used.|
|inhook||CS||Indicate that the given carrier set should be brought into action using the yarn inserting hook when next used. The inserting hook will be parked just before the first stitch made with the carriers.|
|releasehook||CS||Release the yarns currently held in the yarn inserting hook. Must be proceeded by a call to inhook with the same carrier set and at least one knitting operation.|
|out||CS||Bring a set of carriers out of action by directly moving into the grippers.|
|outhook||CS||Bring a set of carriers out of action, using a yarn inserting hook to bring their yarns to the grippers.|
|stitch||L T||Before forming a loop, pull needle by L machine units. After forming a loop, pull needle by T machine units.|
|rack||R||Set the offset of the back bed relative to the front bed.|
|knit||D N CS||Pull a loop formed in direction D by the yarns in carriers CS through the loops on needle N, dropping them in the process. Knitting with an empty carrier set will drop.|
|tuck||D N CS||Add a loop formed in direction D by the yarns held by carriers in CS to those already on needle N. Tucking with an empty carrier set will pull on the stitches without doing anything else (an "a-miss").|
|split||D N N2 CS||Pull a loop formed in direction D by the yarns in carriers CS through the loops on needle N, transferring the old loops to opposite-bed needle N2 in the process. Splitting with an empty carrier set will transfer.|
|drop||N||Synonym for "knit + N".|
|amiss||N||Synonym for "tuck + N".|
|xfer||N N2||Synonym for "split + N N2".|
|miss||D N CS||Move the specified carriers as if they had just formed a loop in direction D at location N. (Not generally needed, used when performing explicit kickbacks or purposeful yarn capture.)|
|pause||Pause the machine until the operator enters a command to continue. (Not generally needed, but can be useful when, e.g., having the operator change yarns.)|
|D||"+", "-"||Direction||A direction on the machine bed. "+" indicates increasing needle number (typically, rightward movement), "-" indicates decreasing needle number (typically, leftward movement).|
|N||"f1", "b-2", "fs3"||Needle||A machine needle. Consists of a location prefix followed by a number. On a V-bed machine, needles are prefixed "f" and "b" for front and back. A V-bed with slide needles adds "fs" and "bs" for front and back sliders.|
|CS||"A B", "2", ""||Carrier Set||List of zero or more carrier names. Carrier names are strings that do not contain the ' ' (space) character.|
|L or T||"2", "-7.5", "30"||Stitch Value||A floating point number giving the number of machine units to retract a needle. Used with the "stitch" instruction. The meaning of a stitch value may vary between machines and manufacturers; be aware that negative stitch values are supported by at least one manufacturer.|
|R||"4", "5.0", "2.25", "-1.75"||Racking Value||Number indicating the offset of the front bed relative to the back bed. That is, at racking R, back needle index B is aligned to front needle index B+R. Needles are considered aligned if they can transfer. That is, at racking 2, it is possible to transfer from f3 to b1. May be fractional on some machines. E.g., on Shima machines, 0.25/-0.75 are used for all-needle knitting.|
Support for extending knitout is supplied through the extension headers namespace (
X-*) and the extension opcode namespace (
Programs that read knitout files should warn upon encountering an extension header or opcode they do not support; but should otherwise ignore the header or opcode.
To aid in debugging, a special type of comment is provided that identifies the source code location corresponding to the current line in the knitout file.
These "source comments" always begin with the string "
!source: ". Anything after this is considered the source location.
Tools that parse knitout files should make no assumptions about the format of source locations, and should print source information intact when reporting errors.
knit + f1 A ;!source: knit.js:53 knit + f2 A ;!source: helper.cpp -- do_knit().2
Knitout operations are straightfoward to interpret when generating machine control code. However, knitout files don't provide any direct guidance on two important issues: carriage passes and kickbacks.
In general, backends should attempt to produce machine instructions that fabricate a given knitout file in as few passes as possible, with the constraint that the result must be "as if" the stitches and rackings were performed one-at-a-time in the order written.
When writing knitout files, one should generally be assume that a backend will at least unify stitches into carriage passes, instead of performing each stitch in its own pass. Backends may go further, unifying stitches with different carriers on different parts of the bed into single passes, or using multiple knitting systems to perform multiple stitches on the same needle in a single pass.
When interpreting knitout files, implementations should maintain a logical position for each yarn carrier that is currently in action. The logical position of a carrier is set and updated by needle operations involving the carrier or the needle to which its logical position is associated.
In practice -- owing to things like yarn carrier stopping distances -- the physical position of a yarn carrier is often different from its logical position. A knitout interpreter must add yarn carrier motions (called "kickbacks" in manual knit programming) to ensure that any differences between the physical and logical positions of yarn carriers are not observable in the finished knit. We call these "implicit kickbacks" and -- among other things -- they make knitout much easier to write colorwork with.
Carrier logical positions are infinitesimally left or right of a needle, which -- for the purposes of this discussion -- we will write by appending a
- to a needle or slider name.
So, for instance, the position just to the right of needle
f3 will be written
This is the same position as
fs3+, but keeping them distinguished is sensible because of the way loop tracking works.
tuck D N CS,
knit D N CS,
split D N N2 CS, or
miss D N CS, the logical position of each carrier in
CSis set to
split D N N2 CSor
xfer N N2, the logical position of any carrier not in
CSthat has logical position
N+is updated to have position
N2+, and similarly for
The "set" rule:
knit + f-3 A ;A has logical position f-3+ tuck - b2 C D ;C and D have logical position b2- split + f3 b3 B ;B has logical position f3+ miss - bs10 E ;E has logical position bs10-
The "motion" rule:
knit + f3 X ;X has logical position f3+ xfer f3 b3 ;X has logical position b3+ split - b3 fs3 Y ;X has logical position fs3+, Y has logical position b3- rack -1 ;logical positions unchanged xfer fs3 b4 ;X has logical position b4+
knit + f1 A ;A has logical position f1+, physical position is likely further right xfer f2 b2 ;A should be kicked left; yarn from f1+ to A's physical position would interfere knit + f10 B ;B has logical position f10+, physical position is likely further right knit + f9 C ;no kickback needed knit + f11 C ;kickback needed: yarn from f10+ to B's physical position would interfere
miss operation to override implicit kickback behavior:
knit + f1 A ;A has logical position f1+ miss + f2 A ;A's logical position set to f2+ xfer f2 b2 ;A should be kicked right (or not at all)
knit + f1 A ;A has logical position f1+, physical position is likely further right miss - f1 A ;A has logical position f1-, physical position is likely further left xfer f2 b2 ;no kickback needed: yarn from f1- to A's physical position is not in the way
This example file uses an alternating-tuck cast-on, followed by two rows of plain knitting, and drops instead of binding off.
;!knitout-2 ;;Machine: SWG091N2 ;;Gauge: 15 ;;Yarn-5: 50-50 Rust ;;Carriers: 1 2 3 4 5 6 7 8 9 10 ;;Position: Right inhook 5 tuck - f10 5 tuck - f8 5 tuck - f6 5 tuck - f4 5 tuck - f2 5 tuck + f1 5 tuck + f3 5 tuck + f5 5 tuck + f7 5 tuck + f9 5 releasehook 5 knit - f10 5 knit - f9 5 knit - f8 5 knit - f7 5 knit - f6 5 knit - f5 5 knit - f4 5 knit - f3 5 knit - f2 5 knit - f1 5 knit + f1 5 knit + f2 5 knit + f3 5 knit + f4 5 knit + f5 5 knit + f6 5 knit + f7 5 knit + f8 5 knit + f9 5 knit + f10 5 outhook 5
This section provides notes on the thinking behind the design choices that went into knitout.
Low-level. The format is low-level. It contains no flow-control, abstractions, or grouping primitives.
Output-oriented. Knitout contains exactly the instructions required to fabricate a knit object.
Debug-able. As an output language, it is important that instructions in a knitout file can be tied back to their source in design programs. Thus, if there is a problem in fabrication or simulation, an error can be reported with a reasonable source location.
Easy to use. It should be simple to write software that reads or writes knitout files.
C: Should we use implicit or explicit kickbacks?
Explicit kickbacks make it easier to write a backend, but harder to write design tools, write knitout files by hand, or to interpret what knitout files are producing.
We expect that more frontend tools will be written than backend tools, and prefer the clarity that comes from not having to constantly think about yarn capture when producing a knitout file.
miss opcode allows frontend authors who wish to schedule their own kickbacks to do so.
It may make sense to introduce an extension header ";;X-Kickbacks: Explicit" to control this behavior.
C: Should the format support 'drop', 'amiss', and 'xfer'?
R: Yes. These are synonyms for 'knit', 'tuck', and 'split' with no yarns; which makes them redundant. On the other hand, they are expected and would certainly be provided by any interface; also, having these in the language avoids the weirdness of needing to specify a left/right direction for a transfer.
C: How to support the wide variety of takedown systems and features? (E.g. fabric presser, rollers, combs, segmented combs.)
R: For now, we leave this for extensions; if common themes begin to emerge, we will make the features core operations. We are likely to support an "x-presser on/auto/off" operation for the SWG backend.
C: One generally can't bring a yarn into action without actually making a stitch with it. Should we combine 'in[hook]' and knitting instructions? Should we require that it be followed by a knitting instruction?
R: We considered, but rejected, several resolutions:
Each of these possible resolutions seems to make it harder to read, write, or understand knitout files. Instead, we changed the language of the specification to make it clear that 'in[hook]' marks carriers to be inserted when next they are used, instead of inserting them directly.
In addition, we suggest that programs that read knitout files should produce a warning if carriers are marked for inserting but not used for a long time.
C: Should the back bed move left or right relative to the front bed for positive racking values?
R: Positive racking values move the back bed right. Here are two justifications, both of which are relatively weak:
(However, in knitout 0.4, racking values worked the opposite way.)