← All projectsHack the North 2026Sep 2026

Morph

Self-folding robot

A chain of 17 cubes that folds itself into one of 88 shapes when you text it.

Top 30of 1,000+ hackers
36 hBuild time
17Cubes, 16 joints that change the shape
43,046,721Joint words: 3^16
88Playable shapes at the booth
From our demo video: the real chain folding into h, t and n

Morph is a chain of 17 cubes. Each cube is cut in half across its body diagonal, and a servo turns one half against the other in 120 degree steps. You text it, a small language model picks a shape it knows, and the chain folds into that shape one planned move at a time.

I built the software that turns a text into motion, and spent 8 hours soldering USB-C breakout boards for the motor controller drivers. Scroll down to watch five texts go through the booth's own classifier and fold plans.

A robot that is not one shape

Most robots have a fixed body: a dog, an arm, a wheeled box. When we were picking what to build at Hack the North, we wanted a robot that was not tied to any one form.

Morph is one open chain of identical cubes. Lying straight it is a line. After a handful of 120 degree turns it is a heart, a letter, a hook. The hardware never changes; the shape is the output.

I built the path from a text message to motion: iMessage in through the Linq API, a MiniLM intent classifier running on our laptop with GPT-4o-mini as a fallback, torque limits on the fold plans, the executor that drives the servos, and MuJoCo validation of every plan before the real robot moves. On the hardware side, all of the wiring runs inside the modules, so I spent 8 hours soldering USB-C breakout boards for the motor controller drivers. My teammates were Daniel Ganjali, Aydan Ling and Justin Rui.

The straight chain starting a fold, from the side

Text it. It folds.

This is the booth without the phone network. Five texts go through the path the robot ran: the bridge's rules, then the booth's own MiniLM classifier, then a shape from our library, then that shape's planned moves, one 120 degree step at a time, on 17 copies of our module CAD.

  1. "show the judges some love"

    No word in it says heart. The bridge's rules pass it on, and MiniLM, running on our laptop, puts heart first at 38.8%, far ahead of "none" at 2.8%. The bridge looks up the heart's planned path, texts back, and the chain folds: 11 moves, one 120 degree step at a time.

  2. "straight line"

    A home phrase. The bridge's rules catch it before any model runs, reply "Going back to a straight line (home).", and every joint goes back to 0. Here the heart's plan plays backwards; the robot drove every joint home at once.

  3. "build a pyramid"

    There is no pyramid in the library. MiniLM's best guess is triangle at 21.0%, just over the 20% it needs to act on its own. The triangle takes 5 moves and ends standing on edge.

  4. "yo whats good"

    Chitchat. MiniLM's top class is none, at 43.3%: the class trained on exactly this. Nothing folds, and the triangle stays. At the booth, GPT-4o-mini got a turn next, and it could only answer with a shape from the same list or "none", in which case the bot asked again. This page never calls it.

  5. "curl up into a spiral"

    MiniLM is surest here: spiral at 85.4%. The triangle unfolds first, backwards, then the spiral's 13 planned moves. The highest torque it asks of any joint is 5.0 N·m, against a 10.6 N·m stall cap.

Blue outline: the wire end (power and the servo bus). Orange outline: the cube whose joint is turning. Joints are numbered from the wire end.

What is real here. The scores and replies: each text was run through the team's own Python pipeline ahead of time (the bridge's rules, then the int8 MiniLM and its fitted head from the repo), and the page shows what it returned. The shapes: the 20 fold plans that are public in the repo (the booth had 88), every move and side copied and replayed against the planner's own recorded poses. The cubes: our module CAD. What is not. GPT-4o-mini is never called; where the booth would ask it, the page says so. Between shapes the page unfolds the last plan backwards; the robot drove every joint home at once.

Seventeen cubes, sixteen joints

Each module is an 80 mm printed cube split along the plane through its center, normal to its body diagonal (the line between opposite corners). A Feetech STS3215 servo turns one half against the other about that diagonal through a 4:1 reduction, so one 120 degree step at the joint is 480 degrees, 5,461 encoder counts, at the servo.

A 120 degree turn about the body diagonal maps a cube onto itself, but it moves the face the next cube is bolted to. So every joint has exactly three positions, -120, 0 and +120 degrees, and the chain always sits on a cubic grid, 82 mm from one cube center to the next. There is no ±240 degree winding: -120 to +120 is two steps through zero. The planner, the robot description (URDF) and the servo driver all share that contract.

Our URDF has 17 revolute joints, one in every cube. The one in the cube at the tip turns a half with nothing mounted on it, and because the turn maps the cube onto itself, it never changes the shape. That leaves 16 joints that matter: 3^16 = 43,046,721 joint words. Most of them drive cubes through each other. The real question is which of the rest look like something.

Problem 27 cubes was too many

We planned 27 modules. The servos were slip fit into PLA housings less than 2 mm thick, not screwed in, and under load the housings flexed and the gears skipped steps. The more cubes hanging off a joint, the worse it got: with the full chain the gears skipped, and 17 was the most the chain could carry.

Fix

At about 5 AM on the last night we cut the robot to the first 17 modules of the 27-module design, with a 17-module URDF, planner config and MuJoCo scene. I switched the text bridge to a new 17-cube shape library and retired the 27-cube one, which had 138 planned folds. Everything at the booth ran on 17.

Next time

Much more robust modules, so all 27 can be chained.

The printed cubes up close: a green half and a black half each
The printed cubes up close: a green half and a black half each

One joint, three positions

One module from our CAD (my teammates designed it; the gear set was hidden when it was exported). The black half stays put and the green half turns against it about the dashed line, the cube's body diagonal.

  1. At rest

    The joint at 0. The blue arrow points out of the face the next cube is bolted to.

  2. Mid-turn: the sweep

    Halfway through a step the green half leaves the cube's outline: at 60 degrees it reaches 22 mm into each of the three neighboring cells across its faces, and into no other cell. That sweep is what the planner has to keep clear.

  3. A full step: +120 degrees

    Through the 4:1 reduction, one step at the joint is 480 degrees and 5,461 encoder counts at the servo. The cube is back inside its own outline, but the face the next cube mounts on now points another way.

  4. Three positions, three directions

    With the next cube on, -120, 0 and +120 degrees send it into three different neighboring cells, each 82 mm from this cube's center. That is why the chain always sits on a cubic grid.

The dashed line is the joint axis; the blue arrow points to where the next cube mounts. Servo angle and counts follow from the 4:1 reduction; the reach is measured on the CAD as it turns.

Calculation How many joint words?

Revolute joints in our URDF17, one in every cubecubot_urdf/n17
Positions per joint: -120, 0 and +120 degrees3the contract the planner, URDF and servo driver share
  1. The tip joint turns a half with nothing mounted on it, and a 120 degree turn maps a cube onto itself, so it never changes the shape: 17 - 1 = 16 joints count
  2. Each of the 16 takes any of its 3 positions whatever the others do: 3 x 3 x ... x 3, sixteen times, = 3^16
  3. 3^4 = 81, 81^2 = 6,561, 6,561^2 = 43,046,721
  4. Counting the tip joint would give 3^17 = 129,140,163 words, but every shape would then appear three times over

43,046,721 joint words for the 17-cube chain.

Why most drawings are impossible

The shape is not a sculpted shell. It is the set of grid cells the 17 cubes occupy, each cube sharing a face with the next. A heart is 17 specific cells, visited in an order the chain can actually thread.

The catch is the roll word: the quarter turn at which each module is mounted relative to the one before it, fixed when the chain is assembled. For our 17-cube chain it is 1200130013310123. Each joint can only swing its own exit face among three directions, so the roll word decides which paths through the grid are reachable at all.

What we learned about which drawings survive:

  • 1-wide and 3-wide strokes thread; 2-wide strokes mostly do not.
  • Long 45 degree diagonals do not thread.
  • Closed rings need a gap, because 17 is odd: on a square grid a closed loop always has an even number of cells.
  • A filled 2 x 2 x 2 block is impossible: a half-swing always reaches 22 mm into a neighboring cell. The same sweep is why the chain can never assemble or escape a 3 x 3 x 3 cube, even though the kinematics could thread one.
  • The wire end carries the servo bus and power. Its cable leaves through a keep-out (an 82 x 40 mm box in the planner) that nothing may sweep through or crush into the table.
The chain bent into a wave on the floor of our work room
The chain bent into a wave on the floor of our work room

Finding shapes worth folding

Recognizability is decided before mechanics, not scored afterwards. Checking whether a drawing can be threaded takes milliseconds; searching for a fold takes about a minute. So the funnel does the cheap tests first and spends fold time only on drawings a judge could already name.

  1. Draw

    Every shape starts as a drawing: 17 cells for our chain (27 for the full one), several per concept. We generated about 8,000 with Claude.

  2. The cheap test first

    Is it a path with two ends and no branches, and does our roll word thread it exactly? That takes tens of milliseconds. In one library run of 282 everyday concepts, 865 of 1,383 drawings passed.

  3. A blind judge

    A judge names every threadable drawing without seeing the concept list. Only drawings it names as what they were meant to be go on: 81 in that run.

  4. Only then, the fold

    The fold search spends about a minute per drawing under the hard checks, and the audit throws out paths that thrash. 66 folded and passed.

  5. Into the library

    Each survivor goes into the library with its path, silhouette, renders and moves. At the booth that was 88 playable names.

StageCountSource
Candidate drawings generated with Claudeabout 8,000my count; 3,330 drawn masks are committed in the repo
One library run: 282 everyday concepts1,383 drawings, 865 threadable, 81 named by the blind judge, 66 folded and passedcubot-v2/docs/LIBRARY-20260919.md
Planned folds for the 27-cube chain, Sep 19138 paths, 116 distinct shapesthe repo's 27-cube library before we switched to 17
Playable at the booth on the 17-cube chain88 namesour booth library
Public in the repo today20 shapescubot-v2/handoff-17, the ones the demo above folds

Drawn masks threaded far more often than generated atlases: about 39% against about 1.6% in the 27-cube study. Not every shape is a faithful drawing: some are the closest 17-cell path this roll word can thread.

The 88 playable shapes of the booth library, each as its cells seen from above
The 88 playable shapes of the booth library, each as its cells seen from above

One fold, move by move

The heart from our public library: 11 moves, exactly as planned. Scroll to fold it.

  1. Seventeen copies of one module

    The chain starts straight on the table, every joint at 0. The blue outline is the wire end.

  2. Move 1: out

    Joint 16, next to the tip, turns +120 degrees. An out move swings the tail: here, only cube 17. It is the cheapest move in the plan.

  3. Moves 2 to 6: in

    Joints 5, 2, 3, 6 and 9. These are in moves: the long tail stays planted on the table and the short base side swings instead, the other way. Each one turns everything built so far. The planner picks the side with the smaller gravity moment about the joint, the one that is easier to lift.

  4. Moves 7 to 11: out

    Joints 13, 10, 14, 11 and 12 finish the shape from the tail end. The highest torque the plan asks of any joint is 1.8 N·m, against a 10.6 N·m stall cap.

  5. Standing on edge

    Because of the in moves, the finished heart stands on edge instead of lying flat, as the planner predicted before the robot ever moved. Its 17 cells match the drawing it started from.

How the planner searches

A move is one joint, one 120 degree step and a side. Out swings the tail. In swings the base side the other way and leaves the tail where it is, which re-orients everything already folded. The planner chooses the side with the smaller gravity moment about the joint, so the heavier side stays planted; when the two are close, it tries both.

Text it, it becomes that

At the booth anyone could text a phone number. The message went through Linq's iMessage API to a webhook on our laptop behind a Cloudflare tunnel. The bridge worked out which shape was meant, looked up its planned path, drove the servos and a MuJoCo mirror at the same time, and texted back.

  1. A text arrives

    Through Linq's iMessage API and a Cloudflare tunnel to the bridge on our laptop, which checks the signature and drops repeats.

  2. Rules first

    Help words and "home" are answered by fixed rules, before any model runs.

  3. MiniLM, then maybe GPT-4o-mini

    MiniLM picks a label on the laptop in a few milliseconds. Only when it is unsure does GPT-4o-mini get a turn, and it can only pick from the same list or answer "none".

  4. Only the library reaches the motors

    A label looks up one planned path in the shape library: its moves, sides, silhouette and torque. Nothing else can reach the motors.

  5. Fold and reply

    The same plan drives the servo bus and a MuJoCo mirror, and the bridge texts back what it is doing, or what went wrong.

The language path

  1. Rules first. Help words get the shape list; "straight line" or "home" sends every joint back to zero. Nothing else runs for those.
  2. MiniLM. A frozen all-MiniLM-L6-v2 sentence encoder, quantized to int8 and committed to the repo (23 MB), plus TF-IDF word and character n-grams, feed one softmax head over 121 shape labels and an explicit "none" class trained on chitchat. "Show the judges some love" has no word in common with "heart" and is carried by the transformer; "d9" against "d6" is a spelling difference the transformer barely sees and the n-grams catch.
  3. A fallback onto the same labels. If MiniLM is unsure, GPT-4o-mini picks from the playable label list only, or answers "none" and the bot asks again. It cannot invent a fold, and it cannot fold a random glyph to fill silence.

The head is a linear softmax fitted in numpy on a 7,578-line corpus written for the robot's own vocabulary, with class-balanced weights so the demo shapes do not win just because they have more rows. Retraining it takes about two minutes on a laptop CPU; nothing in it wants a GPU.

MuJoCo replaying a fold after a text, from our demo video

Problem Int8 moves the embeddings

Quantizing the encoder to int8 moved its embeddings a long way: a mean cosine of 0.958 against the float model when I measured it. A head fitted on float embeddings and served int8 ones would be quietly miscalibrated.

Fix

Fit the head on the int8 embeddings, the same bytes that serve it. The drift is mostly a consistent transformation and a linear head absorbs it: held-out top-1 accuracy stayed at 93.4% either way, and the model went from 90 MB to 23 MB.

Problem Folding filler

Early on, when neither model could tell what someone meant, the bridge still folded something: a plus, a heart, a first letter. In front of judges, a wrong fold takes half a minute to undo.

Fix

The bridge now asks again instead of inventing a shape, and a first letter is only folded when someone asks for a letter or names a person.

What it texted back

Replies from our test runs:

Folding into a square. 4 moves, about 8s. (deciphered using local MiniLM)

Going back to a straight line (home).

I worked out the checkmark fold but couldn't start it. Tell my operator.

The last one is the failure path doing its job: the fold was planned but could not start, and the sender got a plain answer instead of silence. When the USB adapter was unplugged, the same plan played in MuJoCo and the reply said the physical robot was not plugged in.

Earlier, on the 27-cube chain: the bot's replies on the left, the MuJoCo joint panel on the right
Earlier, on the 27-cube chain: the bot's replies on the left, the MuJoCo joint panel on the right

The code

The code is public: github.com/AydanLing/Hack-The-North.

FolderWhat it is
cubot-v2/The offline planner: lattice kinematics, roll threading, the fold search, CAD sweep and torque checks, shape discovery and export
cubot-v2/handoff-17/The 17-cube fold library the bridge plays: one path.json per shape with every move, side and check
cubot_urdf/n17/URDF and MuJoCo scene of the 17-cube chain
imessage/The Linq webhook bridge, the intent model and its training, the GPT fallback, the reply captions, the servo executor and the MuJoCo replay

My part, as the history shows it: imessage/ (the bridge, the classifier and its corpus, the fallback, the hardware executor, the MuJoCo replay with the real servo timing), the planner's holding-load gate and stricter profile, the path-quality audit, and building the 17-cube library the booth played.

Three design choices in it. The kinematics are integer lookups: 24 cube orientations, a table of where each joint state sends the next cube, and an independent floating-point check of the same thing. The fold search checks edges lazily, as above. And the bridge treats a text as data from start to finish: the only thing that can leave the language layer is one label from a fixed list.

Driving the servos

Every servo shares one serial bus on a CH343 USB adapter. The executor soft-zeros the chain lying straight, so a session starts from a known pose. If the chain is still bent from an earlier fold, it drives every joint home first. Then, for each planned move, it sends one joint to its target, polls the bus until it arrives, and re-drives any joint that has sagged.

A connector with four leads soldered and heat-shrunk; every wire in the chain runs inside the modules
A connector with four leads soldered and heat-shrunk; every wire in the chain runs inside the modules

Eight hours of soldering

All of the wiring runs inside the modules, so there was nowhere to hide a loose harness. I spent 8 hours soldering USB-C breakout boards for the motor controller drivers.

The MuJoCo mirror on the laptop and the real chain behind it, folding the same plan

The same plan, twice

Our MuJoCo replay plays any exported path with the real servo numbers: the 10.6 N·m stall as the force limit, and wall-clock pacing at about 65% of the commanded servo speed, which is how fast the chain really moved under load. The URDF is the first 17 modules of the 27-module design, with a free base and a floor, and in moves re-orient the base so standing shapes actually stand.

Judges could watch every fold in the viewer, even when the bus was dark.

Calculation One step, in counts and seconds

One step at the joint, through a 4:1 reduction120°our machine config
Servo encoder4,096 counts a turnFeetech STS3215 12 V
Servo no-load speed at 12 V0.222 s per 60°Feetech STS3215 12 V
Planned time per step2.0 sour machine config
  1. At the servo: 120° x 4 = 480°, and 480 / 360 x 4,096 = 5,461 counts
  2. Servo speed for a 2 s step: 480° / 2.0 s = 240°/s, against 60° / 0.222 s = 270°/s with no load: 89 %
  3. The heart's 11 moves: 11 x 2.0 s = 22 s, the "about 22s" in its reply
  4. At the 65 % pace the chain really moved: 2.0 s / 0.65 = 3.1 s a step, about 34 s for the heart

A planned step asks the servo for 89 % of its no-load speed. The heart takes 22 s as planned and about 34 s at the pace the chain really moved.

Build and test, in order

  1. Night 1

    Soldering and a first stack

    Soldering first, then a short stack of modules standing on a table in the middle of the night.

    One of us testing the first short stack of modules at night
    One of us testing the first short stack of modules at night
  2. Day 1

    Planner, text bridge, 27-cube library

    The planner and the first demo paths landed early. I added the iMessage bridge and the classifier by midday and the GPT fallback after. By evening the 27-cube library had 135 planned folds and I had retrained the classifier on it.

    Printed module parts on the build table
    Printed module parts on the build table
    Assembling modules into the chain
    Assembling modules into the chain
    The chain next to one of us, for scale
    The chain next to one of us, for scale
  3. Night 2

    Bring-up and skipped steps

    First runs on the floor: the base end lifts and flips, bends travel down the chain, and some steps skip. I had wired the executor to the bus with a MuJoCo mirror, so every fold on the floor also played on screen.

    An early multi-joint run on the floor
    The chain in MuJoCo on the laptop at 3 AM
    The chain in MuJoCo on the laptop at 3 AM
  4. Day 2

    27 cubes become 17

    At about 5 AM the gears were skipping with too many modules, so we cut the chain to 17 and I moved the bridge onto a 17-cube library, then kept adding shapes to it: h, t and n came from my own sketches. Full folds on the floor:

    From above: the straight chain starting to fold, one joint at a time
    The same fold finished: an apple
    A fold that goes fully 3D: a loop lifts off the floor
  5. Booth

    In front of a crowd

    A heart for a crowd, letters, and folds that stand up on the table.

    At the booth: the heart forming in front of a crowd
    A flat fold on the booth table while visitors film it
    A flat fold on the booth table while visitors film it
    Adjusting the chain on the table; the laptop shows it folded into h, t and n
    Adjusting the chain on the table; the laptop shows it folded into h, t and n

Results

  • Top 30 of 1,000+ hackers at Hack the North 2026, after 36 hours.
  • A text-to-motion loop that ran at a public booth: a local language model, planned and checked folds, every servo on one bus, a live simulation mirror, and plain-English replies, including when something failed.
  • 88 playable shapes on the 17-cube chain, each one a planned path the robot and the simulator replay the same way.
The four of us with the straight chain; the laptop shows it folded into h, t and n
The four of us with the straight chain; the laptop shows it folded into h, t and n
The finished heart at the booth
The finished heart at the booth
A can on top of the frame fold
A can on top of the frame fold

What I would do next time

Next time

Much more robust modules, so the full 27 can be chained without the gears skipping.

Next time

A better way to generate paths and shapes than drawing thousands of candidates and searching each one.

Otherwise, it worked the way we imagined it.

The limits we already know: the roll word, the odd length, the tethered wire end and one-cube-deep occupancy reject most drawings. Morph is not an unlimited shape printer.

After the hackathon

Later work, not part of what we showed at Hack the North: the chain crawling along a track in MuJoCo.

After the hackathon: the chain crawling along a track in MuJoCo, sped up 12 times