diff --git a/2021/README.md b/2021/README.md
index 6669c6d21f383e17952a98bd6ebd9b02d9d4c7c8..c31634ce6cf4d0014af6e91e8231a8008ae30b33 100644
--- a/2021/README.md
+++ b/2021/README.md
@@ -148,3 +148,20 @@ for part 2, but we shall see...
 Good news! I was wrong about needing to build the cave graph for part 2. I just
 need to specialize my `Cave` inner class to change the rules for adding 
 children.
+
+# Day 13
+
+This looks straight-forward. No fancy data structures required. No clever
+re-framing the problem, either. Creating the "paper" requires a couple of steps
+but no big deal.
+
+Hmm... part 1 took longer than I think it should have. The big-O complexity is
+manageable, but I guess the constant factors are problematic.
+
+For part 2, I'm not even going to try to algorithmically determine which letters
+are created (and not just because I'd have to return soemthing other than a
+long integer).
+
+Hmm... part 2 really didn't take much longer than part 1 did, which suggests
+the computational pain point is in parsing the data and creating the "paper"
+and not in the folding.
diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day13.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day13.java
new file mode 100644
index 0000000000000000000000000000000000000000..19a2497b8cb09c526de171b381076af1b5bbe359
--- /dev/null
+++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day13.java
@@ -0,0 +1,150 @@
+package edu.unl.cse.bohn.year2021;
+
+import edu.unl.cse.bohn.Puzzle;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+@SuppressWarnings("unused")
+public class Day13 extends Puzzle {
+    public record Point(int x, int y) {
+        public Point(String coordinates) {
+            this(Integer.parseInt(coordinates.split(",")[0]), Integer.parseInt(coordinates.split(",")[1]));
+        }
+    }
+
+    private List<String> folds;
+    private boolean[][] paper;
+
+    public Day13(boolean isProductionReady) {
+        super(isProductionReady);
+        sampleData = """
+                6,10
+                0,14
+                9,10
+                0,3
+                10,4
+                4,11
+                6,0
+                6,12
+                4,1
+                0,13
+                10,12
+                3,4
+                3,0
+                8,4
+                1,10
+                2,14
+                8,10
+                9,0
+                                
+                fold along y=7
+                fold along x=5""";
+    }
+
+    private void parseInput(List<String> data) {
+        int maximumX = Integer.MIN_VALUE, maximumY = Integer.MIN_VALUE;
+        Set<Point> points = new HashSet<>();
+        folds = new LinkedList<>();
+        int lineNumber = 0;
+        do {
+            Point point = new Point(data.get(lineNumber++));
+            points.add(point);
+            maximumX = Integer.max(maximumX, point.x());
+            maximumY = Integer.max(maximumY, point.y());
+        } while (!data.get(lineNumber).equals(""));
+        for (++lineNumber; lineNumber < data.size(); lineNumber++) {
+            String line = data.get(lineNumber);
+            folds.add(line.substring(line.lastIndexOf(' ') + 1));
+        }
+        paper = new boolean[maximumX + 1][maximumY + 1];
+        for (int i = 0; i < paper.length; i++) {
+            for (int j = 0; j < paper[i].length; j++) {
+                int x = i;
+                int y = j;
+                paper[x][y] = points.stream().anyMatch(point -> point.x() == x && point.y() == y);
+            }
+        }
+    }
+
+    @SuppressWarnings("DuplicatedCode")
+    private void foldPaper(String fold) {
+        int originalWidth = paper.length;
+        int originalHeight = paper[0].length;
+        char dimension = fold.charAt(0);
+        int seam = Integer.parseInt(fold.substring(2));
+        boolean[][] foldedPaper;
+        switch (dimension) {
+            case 'x' -> {
+                foldedPaper = new boolean[seam][originalHeight];
+                for (int x = 0; x < originalWidth; x++) {
+                    for (int y = 0; y < originalHeight; y++) {
+                        if (x < seam) {
+                            foldedPaper[x][y] = paper[x][y];
+                        } else if (x > seam) {
+                            int mirrorX = seam - (x - seam);
+                            foldedPaper[mirrorX][y] = foldedPaper[mirrorX][y] || paper[x][y];
+                        }
+                    }
+                }
+            }
+            case 'y' -> {
+                foldedPaper = new boolean[originalWidth][seam];
+                for (int x = 0; x < originalWidth; x++) {
+                    for (int y = 0; y < originalHeight; y++) {
+                        if (y < seam) {
+                            foldedPaper[x][y] = paper[x][y];
+                        } else if (y > seam) {
+                            int mirrorY = seam - (y - seam);
+                            foldedPaper[x][mirrorY] = foldedPaper[x][mirrorY] || paper[x][y];
+                        }
+                    }
+                }
+            }
+            default -> throw new IllegalArgumentException("Unexpected fold dimension: " + fold);
+        }
+        paper = foldedPaper;
+    }
+
+    private long countDots() {
+        long numberOfDots = 0;
+        for (boolean[] row : paper) {
+            for (boolean hasAPoint : row) {
+                if (hasAPoint) {
+                    numberOfDots++;
+                }
+            }
+        }
+        return numberOfDots;
+    }
+
+    private void printDots() {
+        // transpose array
+        for (int j = 0; j < paper[0].length; j++) {
+            //noinspection ForLoopReplaceableByForEach
+            for (int i = 0; i < paper.length; i++) {    // goodbye cache friendliness
+                System.out.print(paper[i][j] ? '#' : ' ');
+            }
+            System.out.println();
+        }
+    }
+
+    @Override
+    public long computePart1(List<String> data) {
+        parseInput(data);
+        foldPaper(folds.get(0));
+        return countDots();
+    }
+
+    @Override
+    public long computePart2(List<String> data) {
+        parseInput(data); // reset everything
+        for (String fold : folds) {
+            foldPaper(fold);
+        }
+        printDots();
+        return 0;
+    }
+}