Build log · a living document

Folding a calibration cube out of one square of paper

Live at origami.asasdsdas.com · status: waterbomb base corrected (a composition) — layer-aware engine underway

The goal. A camera-calibration target you can print, fold, and hold: one 200 mm square, printed with a computed pattern, that folds along the classic waterbomb (balloon) base into a 50 mm cube — each of its six faces a ChArUco board. One sheet, single-sided, no glue. Beside it, a self-contained 3-D simulator that not only shows the fold but proves it is physically real: paper that never stretches, tears, or passes through itself.

Where it came from

A flat ChArUco board only calibrates cameras that see it face-on. A cube shows three faces to almost any viewpoint at once — far better for multi-camera rigs. And the waterbomb base already folds a square into a cube-shaped pocket, with exact geometry: the cube edge is the sheet's side over four (200 mm → 50 mm).

So the problem reduces to

(a) compute which patch of the printed pattern lands on which cube face after folding, and (b) prove the fold that gets it there — a rigid-origami motion with no tearing and no stretching. Part (b) turned out to be the deep part.

shipped & verified tried / learned from stumbling block planned
Act I

Stand it up

Get a printable pattern and an animated fold, end to end.

  1. Genesis: pattern, engine, solver, simulator

    Jul 7shipped

    Four pieces in one weekend: a pattern generator (ChArUco boards via OpenCV/ArUco), a fold engine (2-D affine transforms, facet splitting, layer stacks), a cube solver (randomized backtracking over the crease-hinge graph), and a three.js UI. First result: a sheet you could print and an animation that folded it.

    Solver landing near 4.5 / 6 faces covered.

  2. The animation was quietly broken

    Jul 12fixed

    Per-step fold data was keyed by facet id and orphaned every time a crease split a facet, so later steps animated garbage. Rebuilt the per-facet animation arrays to survive splits, and chose each face's ply-stacking order to maximize printed coverage.

    Side faces went from ~75% to 100% printed coverage.

  3. Hidden tears in the "solution"

    Jul 13stumbling block

    Rewrote inflation as hinge-tree kinematics — but discovered the solver could return configurations with torn creases: the repair pass optimized ink coverage without ever checking that shared edges stayed joined. A torn layout had even been cached as "best."

    Added a tear penalty and rejected torn trials. First real signal that looking right ≠ being physical.

Act II

Make it physically real

The demand that reshaped the project: the paper is a rigid, inextensible sheet — no stretching, no tearing, no vertices splitting apart. Prove it, don't assume it.

  1. "The textile is non-deformable"

    Jul 14pivot

    The steering demand. We welded the mesh into rigid panels sharing material vertices (so tearing is structurally impossible to hide) and added three honest metrics measured at zero thickness: tear (do shared points agree?), deform (do panels keep their shape?), and motion (did the fold actually move?). Old code was tearing 1.04 units mid-collapse.

    Also this stretch: an accordion-correct stacking rule, and a teach mode (GPU colour-ID picking) so the ground truth of which facet faces out could be marked by hand.

  2. "It's not 3-D — you're losing fidelity"

    Jul 15fixed

    A sharp catch: facet frames had drifted out of the rotation group (SO(3)) — "a meaningless composition of vectors." An affine two-edge reconstruction was accumulating up to 16% error by the inflation step. Replaced it with an orthogonal Procrustes fit, forcing every placement to be a true rigid motion.

    Orthonormality error dropped to 0.0000 at every step.

  3. The backtrack theory

    Jul 15studied

    A hypothesis worth testing: some folds must transiently move away from their destination, forced by loop closure. We built a rigid-origami mechanism solver in fold-angle space (Newton projection onto the closure manifold) to look for it.

    Confirmed, and stronger than predicted: the book-fold midline reopens ~halfway through the collapse before everything re-closes. The backtracks are real, discovered from the geometry rather than scripted.

  4. A vocabulary of real folds — and a lab to judge them

    Jul 16shippedexposed a flaw

    New rule: every fold must be a named, immutable origami operation — valley, mountain, pleat, reverse, squash — never an ad-hoc reflection. Built foldops.js (the vocabulary) and a Fold Lab that isolates each fold on minimal paper and grades it with the metrics.

    The lab immediately did its job: it flagged the inside-reverse fold as broken — it crumpled (deform 0.04). The base collapses were only ever going to be as correct as their parts.

Act III

The matrix turn

A new tactic: stop patching a 2-D reflection engine and represent the paper the way a GPU would.

  1. Every triangle gets a 4×4 matrix

    Jul 21shipped

    The pivot. Each facet is a triangle carrying an immutable flat shape plus an OpenGL-style model matrix; folds are world-space rotations left-multiplied onto the movers; any crease can bisect a triangle into new matrix-carrying triangles. Two properties fall out for free: rigidity is structural (a rigid matrix can't stretch) and welding is automatic (points on a hinge axis can't move, so a shared edge can't tear).

    Shipped as matfold.js + the Matrix Fold Lab26/26 proofs green.

  2. The reverse fold, finally correct

    Jul 21keystone

    Ported the whole canonical vocabulary onto the matrix engine (Canonical Fold Lab). Simple folds went clean to machine precision. The keystone — the inside-reverse that used to crumple — is now modelled as a degree-4 vertex mechanism where the spine inverts through the vertex (tip = −base), traced by continuation seeded off the flat-fold singularity.

    Inside- and outside-reverse rigid & welded to ~1e-14, the full lab suite green. (A "squash" listed here at the time turned out to be a mislabelled reverse — corrected Jul 22, below.)

  3. The waterbomb bifurcation (a detour)

    Jul 21the hard onewrong target

    The heart of the whole project, and it fought back. Three wrong turns taught three things:

    Why the square wouldn't fold to its triangle

    1. The centre is a degree-8 vertex — a 5-degree-of-freedom mechanism, not the 1-DOF I kept assuming. Every symmetric shortcut sliced that space wrong and produced a cone.
    2. Its flat state is a 2nd-order bifurcation: for a flat sheet the closure Jacobian vanishes, so ordinary continuation literally can't start there.
    3. A straight crease reverses through the vertex (mountain on one side, valley on the other), so the folded triangle is a 5-mountain/3-valley pattern — impossible if each crease held one sign.

    The fix: don't start at the flat state. Seed a folded guess, project it onto the closure manifold (where the Jacobian is healthy), and continue back toward flat. A random-restart search found the branch; it collapses the square straight down to the flat right triangle.

    Rigid & welded end to end — but the target was wrong. This single-vertex collapse is the vertex's BISTABLE mode (a shallow cone), not the flat base (see Jul 22). The solver was sound; the shape it chased wasn't the waterbomb.

  4. Live, and linked together

    Jul 21shipped

    Deployed the static site to the edge (Caddy on vps01, auto-TLS) and wired a consistent nav across every page so the simulator, both labs, the print sheet — and this log — are one traversable site.

    You're reading it at origami.asasdsdas.com.

  5. Mapping the edge of the single-vertex method

    Jul 22investigatedfound a wall

    With the reverse fold and the waterbomb triangle both cracked, the plan was to reuse the same machinery for the next coupled folds — the preliminary base, the squash, the petal. Instead it found an honest boundary. Enumerating every mountain/valley pattern of the degree-8 vertex, it rigid-collapses only to the triangle: the "square" preliminary base is not a single-vertex rigid folding at all. And a squash needs the two plies of a flap to move independently — something a zero-thickness sheet simply can't express. A search of the degree-4 vertex confirmed it: only the trivial fold and the reverse, no distinct squash.

    So a "squash" that had been quietly mislabelled (it was a reverse fold) is now honestly marked planned — and the real next capability is finally clear: an engine that tracks layers.

  6. The waterbomb base was wrong — it's a book fold, not a bifurcation

    Jul 22caught in reviewfixed

    A sharp, correct call: the "waterbomb base" in the lab looked wrong — flaps splayed out, never quite flat. Two things were off. The single-vertex collapse I'd been so pleased with reaches the vertex's bistable cone, not the pressed-flat base; and the base isn't a single-vertex fold at all. The real waterbomb base is a book fold plus two reverse-folds along the diagonals — a composition, exactly what the aggregate simulator already does.

    Rebuilt it that way on the matrix engine, which meant teaching foldAbout to fold a chosen subset of plies about an explicit hinge — the first real piece of the layer-aware engine. It now reaches the correct flat isosceles triangle: base = square side, height = half, four plies per half.

    Rigid & welded throughout, tear ~1e-15. The lesson worth keeping: a clean metric (my "the silhouette is a triangle" check) can still measure the wrong thing. Look at the actual shape.

Where we are → what's next

updated Jul 22, 2026

The matrix engine is proven and the canonical vocabulary runs on it cleanly: valley, mountain, pre-crease, pleat, crimp, and both reverse folds as single-vertex mechanisms; the waterbomb base as a composition (book fold + two reverse-folds) reaching its correct flat triangle. We've mapped where the single-vertex method stops, and taken the first step of the layer-aware engine — folding a chosen subset of plies about an explicit hinge.