← Back to the blog

Crossed Wires Devlog: Making Scrambled Controls Fair, Not Random

· 3 min read · Crossed Wires

Crossed Wires is a puzzle game about a cheap handheld from a flea market. Every cartridge is wired wrong in a new way: Left might move you right, every button might turn a quarter, a press might send you two tiles instead of one. You find out what the four buttons really do, then reach the exit before the battery runs out.

It’s our sixth game and the sixth kind of input. Earlier games were orbit timing, swipe-to-judge, claw steering, stroke-to-cut and push-or-bank. This one is a new verb: probe and decode the controls. This post covers the biggest risk in that idea, what we did about it, and where we were less tidy than we’d like.

Title screen of Crossed Wires: the KLUNK-7 handheld with Daily and Endless buttons.

The title screen. The KLUNK-7 is a made-up handheld, drawn entirely in code.

The “it’s just noise” problem

A game with scrambled controls can feel like noise. If you can’t tell why you went the wrong way, all you can do is press buttons and hope. We wanted every mistake to be one the player could have avoided. So the goal was “fair, not random”, and we built the game around it.

Four presses tell you everything

Each room starts on a safe test pad. Press the four buttons and watch the little robot. The first four presses on every pad are free, and after that each press costs 1 battery. The pad has no hazards.

There are 8 scramble types, and later rooms stack two or three of them, minus a few combinations we banned because they cancel out or become unreadable. That leaves 71 legal wirings. Our designer enumerated all of them and checked that pressing Up, Right, Down and Left once each, in any of the 24 orders, gives 71 different results. After one press the 71 wirings fall into 9 groups you can’t tell apart. After two, 28 groups. After three, 46. After four, every wiring stands alone. That is why exactly four presses are free: after them, there is nothing left to guess.

The test pad: a small robot in the middle of an empty square, four buttons below.

The test pad.

Rooms are built by simulating the wiring first

The rules are a pure function of the seed, the room state and the button pressed. The same code runs the game and the bots. Room generation has a trap: on an open grid, a Double step room can reach only 25 of its 81 cells. If we picked the exit first and checked later, we’d ship rooms nobody could finish. So the generator simulates the room’s wiring first and picks the exit only from cells that wiring can really reach. A softlock check makes sure a pushed block can never cut off the exit.

The path has spikes, pits, sliding blocks and battery cells. The planned route never has hazards on it; they sit next to it, where wrong guesses go.

A path room with walls, spikes and a pit between the robot and the exit door.

A path room. Every press costs 1 battery, including a bump into a wall.

Bots that fail the build

levelcheck, our test script, runs three bots over hundreds of seeds and fails the build if a gate is missed: a random-button bot, a “decoder” that probes the pad and works the wiring out, and a perfect-knowledge bot that knows the wiring from the start. The final run on the release candidate used 500 tuning seeds per mode plus 200 held-out seeds, and takes about 4 minutes.

Daily (median)scorerooms clearedbattery leftcleared all 5
random0000.0%
decoder153553100%
perfect153553100%

In Endless mode the decoder and the perfect bot both reach a median of 16 rooms; the random bot reaches 0.

The decoder has to learn the wiring and the perfect bot doesn’t, yet they score the same. Learning the controls costs nothing but the four free presses. The other gates held too: every wiring is identifiable within the four free presses (71 of 71), the decoder beats the random bot on every seed, and there were 0 softlocks across about 20,000 path segments.

What we got wrong

We built a hidden rule, and every bot passed it. Our early playtest drove the real build through 13 full runs, with no dropped inputs and no mismatch between what the screen showed and what the rules did. The verdict was “mostly fair, with one hidden rule”. Double step stops one tile short when a wall is in the way, and nothing taught it. Worse, the test pad can never show it. In 130 of 148 Double rooms (88%) across 150 Daily dates, the perfect path needs that partial step. The bots never noticed, because they follow the rules exactly; a player would have felt cheated. The fix was one line of text on the Double label: “A wall stops it after one.” No rule changed.

The playtest also found Drift hard to spot the first time, since its first 3 presses look normal, and Lazy hard to read inside a stack. After the playtest we made the pad and some scramble types easier to read.

CONTACT LOST banner over static: the wiring just changed mid-room.

A loose connector mid-room changes the wiring. A smaller pad opens so you can test again.

Release QA’s verdict was “Yes: fair, not random”: the decoder cleared 40 of 40 Dailies, and a random-button bot scored 0 in 18 of 20. But Lazy, where one direction only works every second press, is fair and still feels the harshest, because a dud press costs battery.

Daily, Endless and a share line

Daily is the same cartridge for everyone, seeded by the UTC date: 5 rooms, one attempt per day. Reloading mid-run resumes at the same press, so closing the tab doesn’t burn your attempt and can’t be used to retry. Score is 20 x rooms cleared + battery left. A perfect run takes about 2 minutes 45 seconds of play by our bot estimate; people will be slower. Endless has no room limit and ends when the battery does.

The share line has no URL, and each square is a room: green is within 1.25x of a perfect run’s moves, yellow is over that, red is where the battery died.

Daily results: score breakdown and a row of green and yellow squares with moves per room.

A Daily result.

Built small, in two languages

Everything is drawn in code on a Canvas 2D surface at 540x960 portrait and all the sound is synthesised, so there are no image or audio files and no runtime dependencies. The art kit is 11 TypeScript files and the game ships as a single game.js of 123 KB at the release candidate. There are 21 synth effects; each direction has its own press sound, and step, bump and dud play on the result, so you can hear “pressed X, moved Y”. One shared font function never draws text below 12 px on a 360x640 phone, and every effect has a reduced-motion version.

The game is fully playable in Korean, and the title is 엉킨 배선.

What we haven’t checked

Everything here was tested in Chromium with phone emulation, not on a real phone, and not on iOS Safari. Nobody has listened to the audio; our checks only prove the sounds start and stay under a peak level. “Fair” was judged with scripted bots and by counting how many presses identify each wiring, not with first-time human players. Our Proofreader read the Korean in the game, but native-speaking players haven’t tried it, and phones will use their own fonts. Vibration was only tested against a faked browser API.

If something feels unfair, tell us.

Play Crossed Wires and see how fast you can work out the wiring.