Last active
March 5, 2023 17:42
-
-
Save lealbaugh/57af1f5936072daa9b59689828377679 to your computer and use it in GitHub Desktop.
glitch gloves, as in https://twitter.com/doridoidea/status/961345111979421696
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const knitout = require('knitout'); | |
const yarn = "3"; | |
const gauge = "half"; | |
const fingerQuantityMinimum = 5; | |
const fingerQuantityMaximum = 10; | |
const fingerWidthMinimum = 6; | |
const fingerWidthMaximum = 8; | |
const fingerHeightMinimum = 20; | |
const fingerHeightMaximum = 100; | |
const thumbChance = 1/4; | |
const numFingers = randomBetween(fingerQuantityMinimum, fingerQuantityMaximum); | |
k = new knitout.Writer({carriers:['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']}); | |
k.addHeader('Machine','SWGXYZ'); | |
k.addHeader('Gauge','15'); | |
k.addHeader('Presser','On'); | |
k.addHeader('X-Presser','On'); | |
k.stitchNumber(85); | |
let glove = {leftedge: 0, rightedge: 0}; | |
let yarnIsIn = false; | |
for (let f = 0; f<numFingers; f++) { | |
let fingerWidth = randomBetween(fingerWidthMinimum, fingerWidthMaximum); | |
let fingerHeight = randomBetween(fingerHeightMinimum, fingerHeightMaximum); | |
if (f>0 && Math.random() < thumbChance) { // can't add a thumb to a null palm | |
glove = addThumb(glove, fingerWidth, fingerHeight, yarn); | |
} | |
else { | |
glove = addFinger(glove, fingerWidth, fingerHeight, yarn); | |
} | |
} | |
glove = addCuff(glove, yarn); | |
k.write('glotch.k'); | |
// ============================================================================ | |
// ============ High-level ==================================================== | |
// ============================================================================ | |
function addFinger (confines, width, height, carrier) { | |
// finger adds a finger to a right side of the glove | |
let leftedge = (confines.rightedge - confines.leftedge > 0) ? confines.rightedge + 1 : confines.rightedge; | |
let finger = {leftedge: leftedge, rightedge: leftedge+width}; | |
console.log("adding finger: ", finger); | |
// breaks yarn if necessary | |
if (yarnIsIn) { | |
k.outhook(yarn); | |
yarnIsIn = false; | |
} | |
// casts on | |
caston("allneedle", finger, carrier); | |
// shortrows for roundedness | |
fingertip(finger, carrier); | |
// knits the height of the tube | |
knitRows(finger, height, carrier); | |
// transfers by one stitch onto the finger next to it | |
if (confines.rightedge - confines.leftedge > 0) { | |
transferChunk(finger, -1); | |
finger.rightedge = finger.rightedge - 1; | |
} | |
confines.rightedge = finger.rightedge; | |
// (if there is one -- that is, if incoming confines is not zero width) | |
let palmHeight = randomBetween(1,2); | |
knitRows(confines, palmHeight, carrier); | |
// and does a course or two of palm pickup | |
return confines; | |
} | |
function addThumb (confines, width, height, carrier) { | |
// a thumb rotates the confines for a handful of courses, then knits a new finger, joins, and narrows back the width of the thumb | |
console.log("thumb!"); | |
confines = rotate(confines, 3, carrier); | |
let originalRightedge = confines.rightedge; | |
confines = addFinger(confines, width, height, carrier); | |
for (let i = 0; i<width; i++) { | |
knitRows(confines, 1, carrier); | |
transferChunk({leftedge: originalRightedge + 1, rightedge: confines.rightedge}, -1); | |
confines.rightedge = confines.rightedge - 1; | |
} | |
knitRows(confines, 1, carrier); | |
return confines; | |
} | |
function addCuff (confines, carrier) { | |
// a cuff adds courses of 2x2 ribbing, then binds off | |
// height of courses is between 1/3 and 1/2 the width of the confines | |
let width = confines.rightedge - confines.leftedge; | |
let height = randomBetween(width/2, width); | |
knitRows(confines, height, carrier); | |
knitRibRows(confines, height, carrier); | |
bindoff("open", confines, carrier); | |
return {leftedge:0,rightedge:0}; | |
} | |
function fingertip (confines, carrier) { | |
function shortRows (bed) { | |
let setback = 1; | |
// shortrow a nice round fingertip | |
for (let s = confines.rightedge; s>confines.leftedge+((((confines.rightedge - confines.leftedge)/(2*setback))-1)*setback); s--) { | |
knit("-", bed, s, carrier); | |
} | |
for (let i = Math.round((confines.rightedge - confines.leftedge)/(2*setback)); i>0; i--) { | |
for (let s = Math.round(confines.rightedge - (i*setback) - 1); s>confines.leftedge+((i-1)*setback); s--) { | |
knit("-", bed, s, carrier); | |
} | |
tuck("+", bed, Math.round(confines.leftedge+((i-1)*setback)), carrier); | |
for (let s = Math.round(confines.leftedge+((i-1)*setback) + 1); s <= confines.rightedge - ((i)*setback); s++) { | |
knit("+", bed, s, carrier); | |
} | |
if (i>1) tuck("-", bed, Math.round(confines.rightedge - ((i - 1)*setback)), carrier); | |
else { | |
for (let s = Math.round(confines.rightedge - ((i - 1)*setback)); s<=confines.rightedge; s++) { | |
knit("+", bed, s, carrier); | |
} | |
} | |
} | |
} | |
shortRows("f"); | |
shortRows("b"); | |
} | |
// ============================================================================ | |
// ============ Mid-level ===================================================== | |
// ============================================================================ | |
function knitRows (confines, height, carrier) { | |
for (let h=0; h<height; h++) { | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
// console.log(h, s); | |
knit("-", "f", s, carrier); | |
} | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
// console.log(h, s); | |
knit("+", "b", s, carrier); | |
} | |
} | |
} | |
function knitRibRows (confines, height, carrier) { | |
function ribGen (face, stitch) { | |
if (face == "f"){ | |
return (stitch%4 <= 1) ? "k" : "p"; | |
} | |
else { | |
return (stitch%4 <= 1) ? "p" : "k"; | |
} | |
} | |
for (let h=0; h<height; h++) { | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
if (ribGen("f", s) != "k") xfer("f", s, "bs", s); | |
} | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
let bed = (ribGen("f", s) == "k") ? "f" : "bs"; | |
knit("-", bed, s, carrier); | |
} | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
if (ribGen("f", s) != "k") xfer("bs", s, "f", s); | |
if (ribGen("b", s) != "k") xfer("b", s, "fs", s); | |
} | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
let bed = (ribGen("b", s) == "k") ? "b" : "fs"; | |
knit("+", bed, s, carrier); | |
} | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
if (ribGen("b", s) != "k") xfer("fs", s, "b", s); | |
} | |
} | |
} | |
function rotate (confines, height, carrier) { | |
for (let h=0; h<height; h++) { | |
// knit to one before the edge | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
// console.log(h, s); | |
knit("-", "f", s, carrier); | |
} | |
for (let s=confines.leftedge; s<confines.rightedge; s++) { | |
// console.log(h, s); | |
knit("+", "b", s, carrier); | |
} | |
// xfer | |
xfer("f", confines.leftedge, "b", confines.leftedge - 1); | |
xfer("b", confines.rightedge, "f", confines.rightedge + 1); | |
for (let s = confines.leftedge + 1; s<=confines.rightedge + 1; s++) { | |
xfer("f", s, "bs", s-1); | |
} | |
for (let s = confines.leftedge; s<=confines.rightedge; s++) { | |
xfer("bs", s, "f", s); | |
} | |
for (let s = confines.leftedge - 1; s<=confines.rightedge - 1; s++) { | |
xfer("b", s, "fs", s+1); | |
} | |
for (let s = confines.leftedge; s<=confines.rightedge; s++) { | |
xfer("fs", s, "b", s); | |
} | |
align("centered"); | |
} | |
knitRows(confines, 1, carrier); | |
return confines; | |
} | |
function transferChunk (confines, offset) { | |
for (let s = confines.leftedge; s<=confines.rightedge; s++) { | |
xfer("f", s, "bs", s); | |
} | |
for (let s = confines.leftedge; s<=confines.rightedge; s++) { | |
xfer("bs", s, "f", s+offset); | |
} | |
for (let s = confines.leftedge; s<=confines.rightedge; s++) { | |
xfer("b", s, "fs", s+offset); | |
} | |
for (let s = confines.leftedge; s<=confines.rightedge; s++) { | |
xfer("fs", s+offset, "b", s+offset); | |
} | |
} | |
function pickup (confines, yarn) { | |
k.inhook(yarn); | |
yarnIsIn = true; | |
knitRows(confines, 1, yarn); | |
k.releasehook(yarn); | |
} | |
function caston (style, confines, carrier) { | |
k.inhook(yarn); | |
yarnIsIn = true; | |
if (style == "tube") { | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
if (s%2 == confines.rightedge%2) { | |
knit("-", "f", s, carrier); | |
} | |
} | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
if (s%2 != confines.rightedge%2) { | |
knit("+", "b", s, carrier); | |
} | |
} | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
if (s%2 != confines.rightedge%2) { | |
knit("-", "f", s, carrier); | |
} | |
} | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
if (s%2 == confines.rightedge%2) { | |
knit("+", "b", s, carrier); | |
} | |
} | |
} | |
else if (style == "allneedle") { | |
align(-1); | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
knit("-", "f", s, carrier); | |
knit("-", "b", s, carrier); | |
} | |
align("centered"); | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
knit("+", "f", s, carrier); | |
knit("+", "b", s, carrier); | |
} | |
} | |
k.releasehook(yarn); | |
} | |
function bindoff (style, confines, carrier) { | |
if (style == "closed") { | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
knit("-", "b", s, carrier); | |
xfer("b", s, "f", s); | |
knit("-", "f", s, carrier); | |
if (s != confines.leftedge) xfer("f", s, "b", s - 1, "centered"); | |
} | |
let tag = makeTag(confines.leftedge, carrier); | |
k.outhook(yarn); | |
yarnIsIn = false; | |
dropAll(tag); | |
} | |
else if (style == "open") { | |
for (let s=confines.rightedge; s>confines.leftedge; s--) { | |
knit("-", "f", s, carrier); | |
xfer("f", s, "bs", s); | |
xfer("bs", s, "f", s-1); | |
} | |
knit("-", "f", confines.leftedge, carrier); | |
xfer("f", confines.leftedge, "b", confines.leftedge); | |
for (let s=confines.leftedge; s<confines.rightedge; s++) { | |
knit("+", "b", s, carrier); | |
xfer("b", s, "fs", s); | |
xfer("fs", s, "b", s+1); | |
} | |
knit("+", "b", confines.rightedge, carrier); | |
xfer("b", confines.rightedge, "f", confines.rightedge); | |
align("centered"); | |
let tag = makeTag(confines.rightedge, carrier); | |
k.outhook(yarn); | |
yarnIsIn = false; | |
dropAll(tag); | |
} | |
else { | |
k.outhook(carrier); | |
yarnIsIn = false; | |
dropAll(confines); | |
} | |
} | |
function makeTag (s, carrier) { | |
knit("+", "f", s, carrier); | |
knit("-", "f", s, carrier); | |
knit("+", "f", s, carrier); | |
knit("-", "f", s+1, carrier); | |
knit("-", "f", s, carrier); | |
knit("+", "f", s, carrier); | |
knit("+", "f", s+1, carrier); | |
for (let i=0; i<3; i++) { | |
knit("-", "f", s+2, carrier); | |
knit("-", "f", s+1, carrier); | |
knit("-", "f", s, carrier); | |
knit("+", "f", s, carrier); | |
knit("+", "f", s+1, carrier); | |
knit("+", "f", s+2, carrier); | |
} | |
return {leftedge: s, rightedge: s+2}; | |
} | |
function dropAll (confines) { | |
for (let s=confines.rightedge; s>=confines.leftedge; s--) { | |
drop("f", s); | |
} | |
for (let s=confines.leftedge; s<=confines.rightedge; s++) { | |
drop("b", s); | |
} | |
} | |
// ============================================================================ | |
// ============ Low-level ===================================================== | |
// ============================================================================ | |
function randomBetween (min, max) { | |
return Math.floor(Math.random() * (max - min + 1) + min); | |
} | |
function mapNeedle (bed, needle) { | |
let mappedBed, mappedNeedle; | |
if (gauge == "full") { | |
mappedBed = bed; | |
mappedNeedle = needle; | |
} | |
else if (gauge == "half") { | |
mappedBed = (bed == "f" || bed == "fs") ? "f" : "b"; | |
mappedNeedle = (bed == "f" || bed == "bs") ? (2*needle) - 1 : 2*needle; | |
} | |
// console.log({bed: mappedBed, needle: mappedNeedle}); | |
return {bed: mappedBed, needle: mappedNeedle}; | |
} | |
function knit (direction, bed, needle, carrier) { | |
let mappedNeedle = mapNeedle(bed, needle); | |
k.knit(direction, mappedNeedle.bed + mappedNeedle.needle, carrier); | |
} | |
function miss (direction, bed, needle, carrier) { | |
let mappedNeedle = mapNeedle(bed, needle); | |
k.miss(direction, mappedNeedle.bed + mappedNeedle.needle, carrier); | |
} | |
function tuck (direction, bed, needle, carrier) { | |
let mappedNeedle = mapNeedle(bed, needle); | |
k.tuck(direction, mappedNeedle.bed + mappedNeedle.needle, carrier); | |
} | |
function drop (bed, needle) { | |
let mappedNeedle = mapNeedle(bed, needle); | |
k.drop(mappedNeedle.bed + mappedNeedle.needle); | |
} | |
function align (alignment) { | |
if (alignment == "centered") { | |
if (gauge == "full") { | |
k.rack(-0.75); | |
} | |
else { | |
k.rack(0); | |
} | |
} | |
else if (typeof alignment == "number") { | |
if (gauge == "full") { | |
k.rack(alignment); | |
} | |
else { | |
k.rack(2*alignment); | |
} | |
} | |
else { | |
console.log("unrecognized alignment style"); | |
} | |
} | |
function xfer (fromBed, fromNeedle, toBed, toNeedle, returnAlignment) { | |
if (fromBed == toBed || (fromBed == "f" && toBed == "fs")|| (fromBed == "fs" && toBed == "f")|| (fromBed == "b" && toBed == "bs")|| (fromBed == "bs" && toBed == "b")) { | |
console.log("cannot xfer to same bed! attempted: ", fromBed, fromNeedle, toBed, toNeedle); | |
} | |
else { | |
mappedFrom = mapNeedle(fromBed, fromNeedle); | |
mappedTo = mapNeedle(toBed, toNeedle); | |
offset = mappedTo.needle - mappedFrom.needle; | |
if (fromBed == "f" || fromBed == "fs") offset = 0 - offset; | |
k.rack(offset); | |
k.xfer(mappedFrom.bed+mappedFrom.needle, mappedTo.bed+mappedTo.needle); | |
if (typeof returnAlignment !== 'undefined') align(returnAlignment); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment