Designing Generative Weave Patterns
A weave draft is fundamentally a 4-part data structure. Any generative or computational treatment starts here:
1. Threading - which shaft each warp thread passes through (sequence over N shafts)
2. Tie-up - which shafts each treadle lifts (binary matrix: treadles x shafts)
3. Treadling - order treadles are pressed (sequence over pattern rows)
4. Drawdown - the derived over/under interlacement (computed: threading × tie-up × treadling)
Minimal example — represent as matrices and derive the drawdown programmatically:
Pythonimport numpy as np # 4-shaft straight draw threading (warp thread -> shaft index) threading = [0, 1, 2, 3] * 6 # 24 warp ends # Tie-up: treadle -> shafts lifted (4 treadles, 4 shafts) tieup = np.array([ [1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1], ]) # Treadling: sequence of treadles pressed (weft picks) treadling = [0,1,2,3] * 6 def drawdown(threading, tieup, treadling): ends, picks = len(threading), len(treadling) grid = np.zeros((picks, ends), dtype=int) for p, treadle in enumerate(treadling): lifted_shafts = np.where(tieup[treadle] == 1)[0] for e, shaft in enumerate(threading): grid[p, e] = 1 if shaft in lifted_shafts else 0 return grid pattern = drawdown(threading, tieup, treadling)
This matrix is the substrate for everything downstream: state-machine encoding, grammar induction, or generative variation.
Progress:
- Step 1: Identify the source representation (photo of draft, WIF file, academic paper notation, hand-collected dataset)
- Step 2: Normalize into threading/tieup/treadling/drawdown matrices
- Step 3: Choose computational model matching the analytic goal
- Step 4: Implement transform (dataset → model, or model → new draft)
- Step 5: Validate weavability constraints
- Step 6: Render/simulate and iterate
Step 1: Identify source representation
- Academic handweaving journals (e.g. work on complex/computer-assisted weaves) often present drafts as binary matrices or point-paper diagrams — treat these as your drawdown ground truth.
- WIF (Weaving Information File) format is the de facto interchange standard — parse into the four-part structure directly rather than reinventing schema.
Step 2: Normalize representation
Always separate the generative rules (threading, tie-up, treadling) from the derived output (drawdown). Conflating them makes state-machine mapping much harder later.
Step 3: Choose the computational model
| Goal | Model |
|---|---|
| Sequence-dependent pick generation (twill progressions, satin rotations) | Finite state machine over treadling sequence |
| Constraint-based novel drafts (valid interlacement only) | Context-free grammar or L-system on threading/treadling alphabets |
| Style transfer / novel pattern synthesis from a dataset | Markov chain or small transformer over drawdown row transitions |
| Optimization (minimize floats, balance warp/weft dominance) | Constraint satisfaction / simulated annealing over tie-up space |
| Symmetry-driven generative design | Group-theoretic transforms (wallpaper groups) applied to drawdown tiles |
Default recommendation for "map textile dataset into state machine": model treadling as a sequence of states (one per treadle/shed), where transitions are learned or hand-authored from the corpus. Each state emits a pick vector (row of the drawdown). This gives you both a generative model (walk the FSM to produce new treadlings) and an analytic one (fit existing drafts to infer state graph).
Pythonfrom collections import defaultdict def build_treadling_fsm(treadling_sequences): """treadling_sequences: list of treadling lists from a dataset of drafts""" transitions = defaultdict(lambda: defaultdict(int)) for seq in treadling_sequences: for a, b in zip(seq, seq[1:]): transitions[a][b] += 1 # normalize to probabilities per state fsm = {} for state, nexts in transitions.items(): total = sum(nexts.values()) fsm[state] = {s: c/total for s, c in nexts.items()} return fsm def generate_treadling(fsm, start, length): import random seq = [start] for _ in range(length - 1): state = seq[-1] if state not in fsm: break next_states, probs = zip(*fsm[state].items()) seq.append(random.choices(next_states, probs)[0]) return seq
Step 4: Implement the transform
- Dataset → FSM/grammar: aggregate transition statistics or induce production rules across the corpus.
- Model → draft: sample/walk the model, then run it back through the
drawdown()derivation to get a renderable pattern.
Step 5: Validate weavability
Generative output isn't automatically weavable. Check:
- Float length: no thread should float over/under more than ~5–8 shots (breaks/snags) unless intentional (e.g. overshot).
- Shaft count feasibility: does the threading require more shafts than the loom has?
- Selvedge behavior: edge threads often need special-casing since generative models don't know about them.
- Balanced interlacement: for plain-weave-derived structures, check warp/weft float ratio stays near 1:1 unless a float-heavy structure is the goal.
Step 6: Render and iterate
Render the drawdown as an image (black/white or colored by warp/weft) for visual inspection before physical sampling:
Pythonimport matplotlib.pyplot as plt plt.imshow(pattern, cmap='gray_r', interpolation='nearest') plt.gca().invert_yaxis() plt.axis('off')
Example 1: Input: A dataset of 40 traditional twill drafts (WIF files) with varying treadling sequences. Output: A treadling FSM with states = treadle indices, transitions weighted by empirical frequency. Sampling from the FSM at temperature 0.7 produces novel but twill-family-consistent treadling sequences; drawdown derivation confirms max float length of 3, within tolerance.
Example 2: Input: An academic paper describing a "complex weave" structure via a recursive point-paper motif at 3 scales. Output: Model the motif as an L-system: axiom = base tie-up block, production rule replaces each "on" cell with a scaled copy of the base block. Iterating 2 generations yields an 8-shaft equivalent structure; validate against float constraints before treating as final.
Example 3: Input: Request to "generate 10 new drawdowns visually similar to my huck lace samples." Output: Extract the drawdown matrices from the existing huck samples, train a row-level Markov model (state = previous row's shed pattern, transition = next row), sample 10 new sequences of matching length, render each, and manually flag any exceeding float thresholds for correction.
- Keep threading/tie-up/treadling as the canonical generative representation; treat the drawdown as a cache, not the source of truth — regenerate it, don't hand-edit it.
- When formalizing as a state machine, decide explicitly whether states represent treadles (mechanical/loom-centric) or shed patterns (structure-centric) — they're not the same when tie-ups are non-trivial, and mixing them silently causes bugs.
- Prefer small, interpretable models (Markov chains, hand-written grammars) over opaque ones early on — handweaving structure is highly constrained and rule-based, so interpretability pays off in weavability debugging.
- Cite/ground generative rules in actual structural theory (twill, satin, overshot, huck, doubleweave rules) rather than treating this as generic image generation — the constraints are structural, not aesthetic.
- When mapping academic notation, watch for differing conventions (some journals use warp-face-up as "1", others weft-face-up) — always confirm convention before deriving drawdowns.
- Ignoring float constraints: a statistically generated treadling sequence can be "valid" as a sequence but produce physically unweavable floats. Always re-derive and check the drawdown, never trust the sequence-level model alone.
- Conflating drawdown with treadling as training data: training a sequence model directly on flattened drawdown pixels loses the loom-mechanical structure (shaft/treadle limits); prefer training on the treadling/tie-up level when the goal is a physically weavable output.
- Forgetting selvedge/edge effects: generative models trained mid-fabric will produce edges that don't hold together on an actual loom.
- Overfitting the FSM to one structural family: a state machine trained only on twills will produce degenerate output if sampled for plain-weave-adjacent structures — segment datasets by structural family before training.
- Treating WIF parsing as trivial: liftplan-style WIFs (explicit shaft-lift per pick, no tie-up) require different handling than tie-up-based WIFs — branch your parser accordingly.