Charlie KrugThe Build Log

← All posts

The decode is real. Press base64, and it runs on the actual string.

Peel is a daily puzzle where you unwrap a genuinely obfuscated one-liner one decode at a time. The trick: every puzzle is authored backwards, so the game can prove its own answer at build time.

You open Peel and today's puzzle is a wall of garbage: Cg9GHR0aBx4..., a few hundred characters that mean nothing. You squint at the tail, guess it's base64, and press the button. The layer crossfades away and you get new garbage, this time with %20 and %3B scattered through it. URL-encoding. Press that. Now there's readable punctuation but the words are shifted by thirteen letters. ROT13. Press it, and a real shell one-liner resolves on the board, something short and dumb and worth reading. That's the win.

Why this exists

Deobfuscating a nasty one-liner is a real skill with a real payoff, but the tools for practicing it are professional-grade. CyberChef is the reference: infinitely composable, built for CTF players who already know what a magic-wand recipe does. It has no daily cadence, no score, nothing to share. Meanwhile Wordle and its cousins proved that a small once-a-day puzzle with a shareable result is a habit people build. Nobody had pointed that shape at "decode the weird string." Peel is that: one puzzle a day, nine reversible operations in the toolbox, solve it in the fewest moves.

The decode isn't a cutscene

Here is the part that makes the reveal land. The obfuscated string you see is not a picture of an obfuscated string. It is the actual output of the same transform engine you use to solve it. When you press "Base64 decode," the game runs base64 decode on the current text and shows you whatever comes out. Off-path guesses that don't apply cleanly don't advance anything; the board shakes and flashes red and it costs you a move. There is no scripted animation waiting to play, because there is nothing canned to play. You are really running the transforms.

That raises an obvious authoring problem: how do you build a puzzle whose start state is guaranteed to decode all the way back to a clean plaintext, and not to some near-miss garbage that only looks solved? You author it backwards. A human picks the plaintext first (for the joke), then the engine runs the transforms in reverse to wrap it, layer by layer, into the start state. The solution chain stored with the puzzle is the exact inverse of that wrapping. So the build step can take the shipped start state, apply the shipped chain, and assert the result equals the original plaintext. If a puzzle can't prove it decodes cleanly, it never ships. The wrapping and the solving run through one engine, so there's no authoring format that fakes the visual without a genuine transform underneath.

Difficulty is just chain length plus the occasional decoy: an operation that succeeds syntactically, peels a layer, and drifts you further from the answer instead of closer. The move history marks each step as on-path, an off-path decoy, or a failed decode, so exploration is never blind, and you can undo anything. A puzzle game should punish a wrong final answer, not punish you for looking.

No server, no assets, no rotation logic

Today's date resolves to the same hand-authored puzzle for everyone, so there's nothing to schedule and nothing to sync. Puzzles are static JSON shipped with the build, which means the whole game is a static site with zero backend, free to host forever and trivially cached. Even the sound is weightless: the hover, success, fail, and win effects are synthesized in WebAudio at runtime, so there isn't a single binary audio file in the repo. The board is one Canvas 2D element with a phosphor-green CRT look, and the engine and game state sit at 100% line and branch coverage. The transform math is on GitHub if you'd rather read it than trust it.

Try it

Open Peel, read the garbage, and look at the tail of the string for a tell: trailing = means base64, %-escapes mean URL-encoding, all-hex means hex. Pick the operation you think unwinds the outermost layer, and repeat. When the plaintext resolves, the timer freezes and you get a spoiler-free result grid, one square per move, to paste wherever you brag.

Peel is live. Free, in your browser, no signup.

This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.

Comments

Loading comments…