All work

Penalty Challenge

A penalty shootout for an LED wall, built in Unity and C# for a World Cup season. It's played from two iPads: one for the kicker, and one shared by one or two goalkeepers. The iPad controller pages are HTML, CSS and JavaScript, linked to the game through a Node.js WebSocket relay.

At the conference: the keepers make a save, then win the match.

The problem

The church's weekend of 18 and 19 July 2026 fell in the World Cup season, so the LED wall needed a football game. It had to be played by two sides at once, against each other: a kicker taking the penalties, and goalkeepers trying to save them.

The constraint

I had 2 weeks to build it.

  • Two iPads, one game. One iPad was for the kicker and one for the goalkeepers, and both had to drive the one game running on the wall.
  • Nobody at the PC. The station ran unattended, with no keyboard at hand, so the game had to look after itself between players.

What I tried

I split it into four parts:

  • The game. Unity and C#, running on the PC that drives the LED wall. It holds all the rules: it flies the ball, decides whether each shot is a goal or a save, and keeps the score.
  • The controller pages. Each iPad opens a webpage written in HTML, CSS and JavaScript, so there's no app to install, just a browser on the same network.
  • The relay. A small Node.js WebSocket server. It has no game logic: it passes every message to every other client. A shot goes from the kicker's page, through the relay, to the game, and the result comes back the same way to both pages.
  • Catching up. The game re-sends its state every second, so a page that connects late, or an iPad that reloads, catches up on its own.

I also chose an automatic reset to the title screen after a minute with no input over waiting for staff to reset it, so the next player always found a fresh game.

The first version's controls were simple:

  • The kicker picked one of four corners to shoot at.
  • The keeper was steered by a crowd. The keeper page had four corner buttons, and the keeper moved towards whichever corners were being held, pulled harder the more fingers were on one, up to four.

What failed

  • The keeper was too slow. On the first day, the keeper took too long to get across the goal.
  • The keeper was left parked in a corner. When a group walked away, the keeper stayed wherever their last votes had pulled it, so the next people found it sitting in a corner.

What I changed

  • A faster keeper. I raised the keeper's speed on the first day.
  • The keeper goes home. On the second day, I made the keeper drift back to the middle of the goal once nobody had pressed anything on the title screen for 4 seconds.

Then I rebuilt the controls for a conference the following week:

  • One kicker against two keepers. The keeper page became two joysticks, one on each half, and each player steers their own glove. A stick gives a clean direction and amount, where the votes had to be blended into one pull.
  • Aim anywhere, with power. Instead of picking a corner, the kicker drags on the pad to aim anywhere in the goal, and the length of the pull sets the power. Past the white mark, the extra power can lift the ball over the bar, which gives the keepers the point. Shots at the top of the goal curl; low shots fly flat.
The two controller pages at iPad size. Left, the kicker page: a ball dragged up and to the left on a green pad, with a dashed aim line and a power bar filled to just under its white mark. Right, the keeper page: a blue screen split into Player 1 and Player 2 halves, each with a joystick for one glove
The reworked controller pages, both connected to the relay. The kicker's pull is just short of the white mark; on the keeper page, each player steers one glove from their half.

What happened

It ran on 18 and 19 July 2026, and the reworked version ran at the conference the following week.

The full clip from the conference.

Since then, I've made a generic version that isn't tied to either event and runs on an ordinary 1920×1080 screen.