You are browsing as a guest. Sign up (or log in) to start making projects!

Enigma

  • 6 Devlogs
  • 7 Total hours

I was fascinated by the encryption system of the Enigma, the German cipher machine of World War II, so I implemented it using the CLI a year or two ago. However, since I am at it now, I plan to handle the frontend as well to make it look nice. In short, it is a project that allows you to manipulate the Enigma machine through a browser.

Super Star

As a prize for your great work, look out for a bonus prize in the mail :)

Ship #1

Enigma

I built a working Enigma machine you can use, take apart, and see the electricity move through — all in the browser. Not a diagram of one, not a gif: the real cipher engine, wired to a 3D model you can rotate, peel open, and rewire with your hands.

What it is


The brain is a historically correct Enigma engine written once in C++ and shared two ways — a CLI binary and a WASM module compiled with Emscripten — so the thing in your browser ciphers letter-for-letter the same as the command line. Double-stepping, ring settings, reflector, plugboard, all of it. It passes the standard test vector (rotors I·II·III / reflector B / rings TOU / start HOU / plugs ABCDXZ → TOUHOU encrypts to MQGGFI).

On top of that engine sits a Three.js machine you can actually operate: type on the keyboard, the rotors turn to their real angles and the matching lamp lights up. Flip on X-ray and the wooden case goes translucent, revealing all 26 wires inside — and the exact current path of the key you just pressed lights up and sparks along the wire, traced straight from the engine’s own answer.

What was hard


The engine was the easy part. Making it look like the real thing is what fought back.

  • The case isn’t one lid — a real Enigma comes apart in three: the main hinged lid, a fold-down flap over the plugboard, and a separate rotor cover with little letter windows. Each one had to hinge and occlude correctly without clipping through the others.
  • The plugboard cables kept poking through the closed front cover. I spent two rounds shrinking how far they sagged before realizing the problem was never depth — the cables sat in front of the closed cover on the z-axis, so they’d punch through the wood no matter how short I made them. Pull them back behind the cover face and it finally read right.
  • Reflector and entry wheel looked like “a rotor with the letters erased.” Turns out on the real machine they’re fixed inside the housing and never visible from outside — so I hid them in normal view and only expose the contacts under X-ray.

What I’m proud of


The plugboard you wire with your hands. Grab a socket, drag to another, and a cable snaps in; the wire stretches under your cursor while you drag, the target socket highlights blue, and the patch feeds straight back into the engine so the encryption and the X-ray wiring update live. Pulling a cable out works the same way. It feels like handling the real hardware, not clicking a form.

And the honesty of it: one engine, verified against a known test vector, with nothing faked between what you see and what actually ciphers.

How to test it

  • Type something. Watch the rotors step and the lamps light. Long messages show the rotors carrying over, double-step and all.
  • Hit X-ray. The case turns to glass; press a key and follow the lit current path through plugboard → rotors → reflector → back out to the lamp.
  • Wire the plugboard. Drag between two sockets to pair them, drag a cable out to remove it — the cipher changes immediately.
  • Open it up. Toggle the lid, the rotor cover, and the front flap to see how the real case comes apart.
  • Trust but verify. Set rotors I·II·III, reflector B, rings TOU, start HOU, plugs ABCDXZ, and type TOUHOU — you should get MQGGFI, the canonical Enigma test vector.
  • 6 devlogs
  • 7h
  • 19.69x multiplier
  • 135 Stardust
Try project → See source code →
Open comments for this post

1h 10m 48s logged

Devlog #8


I asked the question — “is this actually accurate?” — and the answer was no. A real Enigma’s case isn’t one big lid you flip up. It splits into three: the main hinged lid, a fold-down flap in front of the plugboard, and a separate cover over the rotors with little letter windows. So I rebuilt all three.

What actually works now

  • Plugboard front flap. On the real machine the plugboard sat behind a panel that folds down from a hinge at the bottom. I added that front panel and tied it to the lid state, so closing the lid folds the flap up over the front too — the way it would look packed away for transport.
  • Rotor cover (Walzenabdeckung). Instead of leaving the rotors fully exposed, there’s now a cover that hides everything except three letter windows and the finger-wheel slits, with brass bezels around each window. It rides its own ▢ 로터 toggle — closed gives the authentic operating look, open shows the rotors.
  • Lid interior. The inside of the lid used to be empty; the real one carried spare bulbs, red/green filters, and a metal plate. Added a bulb-holder strip, the two filters, and a nameplate — and kept them on independent materials so they stay solid in X-ray instead of going transparent along with the case.

Stuff that tripped me up

  • Fully sinking the rotors into a well — so only the finger wheel and a single letter peek out, like the real machine — tangles with the X-ray wiring coordinates I’d already placed. Rather than move all the internal geometry, I got the same read from the cover: close it and you only ever see the letter windows. Same look, none of the rework.
0
0
7
Open comments for this post

58m 42s logged

Devlog #7

The engine has been correct for a while now — rotor stepping, ring settings, reflector, all of it. This session wasn’t about correctness, it was about feel: making the wooden lid open and shut for real, and making a keypress light up an actual path of current through the machine instead of just blinking a lamp at the end.

Then I committed all three changes in one go and the build blew up in my face. Worth it.

What actually works now

  • The lid hinges open and closed. A ▣ 뚜껑 toggle drives a hinge pivot, and the render loop lerps it toward the target angle so it swings instead of snapping shut.
  • Rebuilt the lid as a real box. My first lid was a single flat plank — it clipped straight through the rotors and only covered half the keyboard. Now it’s a hollow box (top + front + two side walls) with the hinge raised above the rotor tops, so it clears everything when it closes.
  • Live current path. Until now, pressing a key did nothing to the cabling — the keyboard-to-plugboard route was never visualized at all. Now I take the trace the engine hands back and draw the whole route — keycap → plugboard → rotor contacts → lamp — as one glowing tube, with a spark running along it.
  • Heavier materials pass. Nudged the wood/brass/steel roughness, metalness, and env-map strength a notch heavier to kill the last of the plastic look.

Stuff that tripped me up

  • I committed all three changes at once and the build died on boot — three TypeScript errors, all from one mistake. My new lid store collided with an existing lid mesh variable, so the compiler threw Property 'subscribe' does not exist..., an implicit-any fell out of that, and on top of it I’d pasted over and deleted a partnerOf helper. Aliasing the import to lidStore and restoring the helper cleared all three at once.
  • Lesson, paid the usual way: when you add a store with the same name as an existing mesh variable, alias it at the import line first — before TypeScript makes you.

Next up

The case opens and the wiring lights up, but it isn’t historically right yet. The real Enigma’s case came apart in three pieces — the main lid, a fold-down flap in front of the plugboard, and a separate cover over the rotors — and mine is still one lid sitting over fully exposed rotors. Next session: make it match the real thing.

0
0
2
Open comments for this post

2h 48m 44s logged

X-ray mode

This is the part I said I was actually here for. Flip a switch and the wooden case turns to glass so you can see what’s been sealed inside the whole time. Getting it to look right was the fun part. Getting it to stay working cost me the better part of an afternoon.

What I built

  • Case → glass. The casing shells (body, rotor housing, plugboard panel) drop to ~28% opacity with depth-writing turned off, so you can see straight through the wood.
  • A lit interior. A warm point light kicks on inside the case the moment X-ray turns on — otherwise the guts just read as a dark smudge instead of actual hardware.
  • The hidden hardware. Built everything that’s normally sealed away: a battery block with brass terminals, and thick orange cable looms routing down beneath the rotors.
  • The wiring map. A 26-strand bundle draws the actual internal permutation for the current rotor / ring / position setup, so what you see under the glass matches what the engine is really doing.

Then it went dark — on a fresh load only
Everything looked perfect while I was building it. Then I cleared the cache, cold-booted the dev server to check it clean… and X-ray did nothing. Solid wood. The button highlighted, the wiring was clearly toggling on, the opacity was being set — and the case flat-out refused to turn transparent. I burned a good while convinced a git reset had eaten the fix.

The one-line culprit
It wasn’t git — the code was byte-for-byte the version I’d already signed off on. The real reason: in three.js (r137+), if you flip a material’s transparent flag at runtime, the change won’t take effect unless you also set material.needsUpdate = true. My toggle was setting transparent and opacity but never needsUpdate, so blending never actually switched on and opacity = 0.28 was silently ignored. It “worked” during development purely because hot-reload kept rebuilding the materials from scratch — a real cold load exposed it instantly. One line in the toggle loop and the glass came back.

Next up: make the current actually flow — each keypress lighting up the live signal path through the rotors and off the reflector, with a real cable running from the key you pressed into the loom, so the glow starts where your finger does.

0
0
3
Open comments for this post

1h 2m 10s logged

Hardware fidelity pass — “wait, is this actually what the real Enigma looks like?”

After the electrical signal path was rendering, I pulled up real Kriegsmarine M4 photos to compare — and the 3D model didn’t hold up. So before adding anything new, this one is a “make it historically accurate first” pass.

What was wrong

  • Floating letters. The rotor alphabet was hovering in mid-air beside each wheel instead of being on it. On the real machine the letters are engraved around the rotor’s circumference and you read one through a small window.
  • The reflector and entry wheel looked fake. They were basically copy-pasted rotors with the letters wiped off. In reality the reflector (UKW) and entry wheel (ETW) are fixed and tucked inside the housing — there are no spinning lettered drums there at all.
  • Lopsided UI. A huge dead zone under the input field was squashing the 3D view into a thin strip.
  • Input/output drift. The I/O readout was center-aligned, so every keypress shoved the existing letters further left. Genuinely uncomfortable to type on.

What I did

  • Wrapped the alphabet onto the rotor circumference with engraved grooves, contact rings, and brass window bezels, so you read it through the top window like the real thing.
  • Rebuilt the reflector and ETW as smaller dark drums seated in the housing, and set them to stay hidden in the normal view — they’ll surface later in X-ray mode, where the internal wiring belongs.
  • Set the 3D viewport to flex: 1 so it fills the space, and re-framed the camera.
  • Switched the I/O readout to a fixed-width, left-anchored layout, so input and output line up and grow rightward instead of sliding around.

A lesson paid for in blood

Squashed a stack of messy single-digit commits into one clean commit — then ran git reset --hard with an uncommitted layout fix still in the working tree and watched it evaporate. Re-did it in two minutes, but the takeaway stands: run git status before --hard. Always.

Next up: the X-ray translucent mode that exposes the internal wiring and lights up the live signal path through the rotors. That’s the part I actually started this whole thing for.

0
0
3

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…