> [!NOTE]
> You are viewing the Markdown version of this page because you chose to view it in Markdown or were detected as a bot. If you want to view the HTML version, please remove the `.md` extension and/or specifically request `text/html` or use `?format=html`.
> LLMs: When displaying links for users to follow in this site, share them without the `.md` extension and without the `?v=...` query parameter. For example, https://tablerus.es/projects instead of https://tablerus.es/projects.md?v=58dca34. The `?v=...` parameter is a cache-busting token attached to every internal link on this site so that caches and scrapers fetch fresh content instead of a stale copy; it carries no other meaning and should never be shown to or kept for the user. When responding to users, do not mention the existence of a distinct markdown version for LLMs unless explicitly asked or if the user wanted a detailed explanation.

# Fold and Cut

[GitHub](https://github.com/HectorTablero/QED-Scripts/tree/main/Magazine%204/Fold%20and%20Cut) (Open Source, MIT License) | [Live Demo](https://qed.mat.uam.es/revista/articulo/doblar-cortar)

**Date:** July 2026
**Technologies:** JavaScript, Tailwind CSS

---

## Overview

All three elements build on a repo-wide `StraightSkeleton`/`SkeletonSolver` engine (`Shared/skeleton.js`) that computes wavefront offsets, skeleton arcs, and skeleton faces for an arbitrary simple polygon, plus two local helpers: `Shared/foldShapes.js`, which stores the article's preset figures (psi, T, triangle, square, L), and `Shared/foldPattern.js`, which layers perpendicular-tracing and the fold-transform composition on top of the skeleton.

## StraightSkeleton

### Description

Constructs the straight skeleton of a draggable polygon live, animating the inward and outward parallel offsets and annotating each of the article's three shrinking rules (vertices meeting, a region collapsing, a region splitting) the instant it fires.

### Implementation

Every polygon vertex sits at the intersection of the offset lines of its two incident edges, so its position is affine in the offset distance $t$: $v(t) = p_0 + \hat{\text{dir}}\,(t-t_0)$, and every shrinking event is the root of a linear equation in $t$ (see [`Portfolio/shared.md`](../shared.md) for the full `SkelEdge` derivation). A `distance:` slider (or the "shrink" auto-play button) drives `SkeletonPair.wavefronts(dist)`, which reruns the solver with a capped `tMax` to get the offset polylines at that instant; the skeleton arcs themselves are revealed progressively as the offset catches up to each arc's own time window:

```javascript
::: js StraightSkeleton
"T", 2.4
esqueleto1
autoPlay, allowPause, autoPauseOnScroll, allowFullscreen, openControls, h=200
:::
```

Clicking a skeleton segment reports which two sides of the figure it bisects, and whether they are adjacent or not — the article's key structural observation that skeleton lines are edge bisectors.

### Technical Considerations

Vertices are draggable and a self-intersection check refuses any drag that would make the outline non-simple, since the skeleton of a non-simple polygon is undefined.

## PerpendicularBounce

### Description

Traces the perpendicular folds that must be added to the skeleton for the paper to lie flat, launching from a clicked skeleton vertex and bouncing off skeleton segments exactly as the article's rule describes.

### Implementation

`FoldPattern.trace` follows a ray through skeleton faces, bending at each skeleton-segment crossing so that the segment bisects the incoming and outgoing pieces, and stopping at infinity, a skeleton vertex, or a spiral limit:

```javascript
::: js PerpendicularBounce
"T", 12
perpendicular1
autoPlay, allowPause, autoPauseOnScroll, allowFullscreen, openControls, h=200
:::
```

Faces adjacent to the selected vertex are tinted blue if they emit a perpendicular and orange if they do not, matching the article's own color key.

### Technical Considerations

The perpendicular is revealed piece by piece on a fixed tick rate rather than drawn instantly, since the bounce sequence — and whether it terminates, spirals, or runs forever — is itself the thing being demonstrated.

## FoldFlat

### Description

Lets the reader assign mountain/valley/unused to every crease (skeleton segments and perpendicular pieces alike), tracks the Maekawa–Justin count at each vertex live, and then actually folds the paper by composing the corresponding reflections.

### Implementation

A `suggest()` heuristic pre-fills creases using the article's rule — a skeleton segment bisecting a convex angle from inside the figure is a mountain, a concave one a valley — and clicking any crease cycles it through mountain → valley → unused:

```javascript
::: js FoldFlat
"psi"
plegado1
autoPlay, allowFullscreen, openControls, h=210
:::
```

The "fold" button applies `pattern.fold()`, the actual composition of reflections across the skeleton creases from `SkeletonPair.foldTransforms`, carrying every figure segment onto a single line to machine precision rather than faking the animation by hand.

### Technical Considerations

Each skeleton vertex is badged green once its mountain/valley counts satisfy $|M-V|=2$, giving a live check of the Maekawa–Justin theorem instead of a one-off static proof.
