The Machine That Started It All

ORIGIN

It was a Saturday afternoon in October sometime in the eighties at the local shopping centre, the kind where you drifted between the record shop and the toy store just to see what was there. I had five kroner in my pocket from returning empty bottles, and the Red Cross Ray T6 was hanging below the escalators next to the kiosk exactly where it always was.

The R columns were already almost full.

That mattered.

You could see every coin stacked behind the glass, and both R gates were only a couple of hits away from paying out five coins. Somebody else had done most of the work already. All I had to do was finish it.

My friends stopped behind me as I fed the first coin into the slot.

It rattled down the side channel and settled into the flick position with that tiny metallic click I can still hear in my head. I aimed for the 10 gate immediately, of course I did, and snapped the coin forward. It clipped a peg and missed.

The machine always did that. It punished greed.

So I switched tactics.

The R gate was safer. Slower. I started building the column one coin at a time, flicking carefully, learning the angle, watching the stack creep higher behind the glass. Misses piled up. A few clean shots landed. The machine felt alive, every gate behaving differently depending on how the coin struck the pegs.

Six hits.

Then seven.

The payout dropped with a sharp clatter into the tray: five coins back.

That sound was magic.

I shoved them straight back into the machine before the excitement could wear off. Now I had momentum. I mixed careful R-gate builds with quick shots at the 3 gate, chasing points while trying not to lose the rhythm. Coins bounced. Friends shouted advice. Someone behind us waited for their turn.

Then it happened.

A clean line toward the centre.

The coin slipped between the pegs, disappeared for half a second, and the machine answered with the best sound in the world.

Ten coins spilled into the tray.

I counted everything quickly.

Twenty-five kroner.

I scooped them up before the next kid could step forward, and we walked straight to the candy shop feeling like we had beaten the system.

What the Digital Version Does — and Adds

OVERVIEW

Staying true to the original

The layout of the digital version maps directly to the Ray T6: nine gates across the back, with an R gate at each end and numbered scoring gates in between. The coin columns beneath the R gates fill as you hit them, just as they were on the cabinet. The pegs above each gate are drawn to show their configuration, so you can read the board before you aim — the same information you had the physical machine.

The flicking mechanic translates to mouse, controller, touch and keyboard. On a phone you drag and release to aim and fire; on desktop you pull back from the launch ring The coin bounces off the cabinet walls, settles into columns, and behaves as you would expect a real coin to behave — including the frustrating near-misses that were a staple of the original.

Daily challenge

Every day at midnight UTC the gate layout — peg positions, tensions, R column starting counts — updates to a new fixed seed shared by every player. Play the daily and your score goes into a pool with everyone else who played that day. It is the closest digital equivalent to two people standing at the same cabinet.

Leaderboard

Every daily score is recorded on a global leaderboard, visible at knipsekassen.no/leaderboard. You can browse the top scores for any date, page through to find your own rank, or jump straight to a position number. Your rank appears on the result screen after each daily game with a direct link to the page where your score sits.

Sharing

After a round you can share your result as an image — a card showing your score, tier and the gate seed — or copy a link that lets anyone replay the exact same layout you just played. Share links work for both daily and free games, and opening one restores the full peg configuration so the challenge is identical.

Unlockables

Currently three things can be unlocked through play, none of them affecting the core scoring:

Going forward new unlocks will be added regularly either as seasonal or monthly events or special challenges.

Monthly challenges

Alongside the daily challenge, occasional monthly events give every player a shared goal. Completing the goal unlocks a secret new cabinet permanently for all players.

The May Challenge asked players to collectively play one million coins. The goal was not reached, but it set the baseline for what comes next. The June Challenge is now live — the goal is 10,000 completed daily challenge games before the end of June. Monthly challenges are accessible from the menu and at knipsekassen.no/june-challenge.

Technical Details and Challenges

Technical

This section covers the engineering decisions behind the game — what we tried, what broke, and why things ended up the way they did.

Getting Coins to Behave

Technical

The first big decision was which physics engine to use. We tried Matter.js early on and ran into the same problem repeatedly: coins stacking inside columns would slowly drift and clip through each other during quiet frames. Matter.js uses an impulse-based solver that handles fast collisions well but struggles with resting contact — objects that are just sitting on top of each other. For a game where most of the interesting state is a pile of coins sitting in a column, that was a dealbreaker.

We switched to Planck.js, a JavaScript port of Box2D. Box2D uses a constraint solver that iterates over contact points every step, which makes stacking stable. The tradeoff is tuning: every surface needs friction and restitution values that feel right together, and getting a coin to slide naturally off a peg rather than sticking or bouncing wildly took a lot of back-and-forth.

Gate entries were their own problem. A coin that grazes the edge of a gate opening should bounce away; one that enters cleanly should register as a win. Early on, coins would catch on the inside edge mid-flight and trigger a win on what was clearly a miss. We solved this by adding a settle-time check: a gate contact only counts if the coin has been inside the sensor region for more than a minimum number of physics steps. It is a small thing, but it is what makes the gate feel fair.

Coins also had a habit of getting wedged in corners and vibrating indefinitely. Rather than fighting the physics, we detect low-velocity coins that have been stationary for too long and nudge them slightly — just enough to let gravity resolve the situation without turning off the simulation.

19 Characters, Infinite Layouts

Technical

Every game layout in Knipsekasse is fully described by a short string — 19 characters in the current format. That string encodes peg positions above each gate (three states each, packed as a base-3 number into three base-36 characters), two sets of peg tensions (nine values from 1–10 each, packed as base-10 into six base-36 characters each), starting counters for the two R columns, wild port state, and the cabinet colour. No database lookup, no server round-trip — you can reconstruct the entire board from the seed string alone.

The format has gone through three versions as we added features. V1 was 16 characters and Classic-only. V2 added a mode prefix — one character for Classic, Sprint, or Blitz — making it 17. V3 added a two-character field at the end for wild port and cabinet colour, bringing it to 19. The key constraint throughout was backward compatibility: an old V1 seed shared in a message or a URL should still work today, and it does.

The daily seed is generated deterministically from the date. We run the date string through a hash function, use different hash rounds for peg positions, left tensions, right tensions, and extras, and combine them. Every player on the same calendar day gets the same layout without us storing anything. Sprint and Blitz daily challenges use a different salt so they get a distinct board from the Classic daily.

The same seed can be shared as a URL — ?seed=XXXXXXXXXXXXXXXXXX — and opening it loads exactly that layout for free play. This is how the share-after-win feature works: the win screen builds a URL from the current encoded seed and puts it on the clipboard.

Making the Frame Budget

Technical

At peak the simulation runs 60+ live physics bodies simultaneously. On a fast desktop that is nothing, but on a mid-range phone it was enough to push frame times well above 16ms and make the game feel sluggish. Profiling showed the bottleneck was not the physics loop — it was everything around it.

The biggest single win was skipping sprite-sync loops for coins that are not moving. Every frame we had been iterating over all bodies to update their Phaser sprite positions. Most of those coins are sitting stationary in columns. We added a velocity threshold check and only sync bodies above it; static field coins are skipped entirely. That alone dropped iteration count from 60+ to 1–3 on a typical frame.

We also reduced maxSubSteps from 5 to 3. Sub-steps let the physics engine subdivide a long frame to maintain accuracy, but five sub-steps on an already-slow frame just made the next frame slower. At three the simulation is still accurate enough — coins move slowly enough that missing a sub-step does not cause tunnelling — and slow frames stop cascading.

The HUD was making DOM layout queries every frame to position its elements. We cached all element references at startup and switched to dirty-checking: only write to the DOM when a value has actually changed. We also moved audio to MP3 across the board — WAV files are large, and the decode cost was showing up at game start on slower connections.

We prototyped moving the physics loop to a Web Worker to free the main thread entirely. It worked, but the overhead of serialising and deserialising body state across the worker boundary every frame was larger than the time we saved. With the DOM fixes in place, the main thread had enough headroom and we shelved the worker.

A Score Board With No Backend Team

Technical

Adding a global leaderboard to a static site means introducing a database and server-side logic without the infrastructure to run servers. We landed on Supabase for storage and Netlify Functions for the API layer — both have generous free tiers and neither requires managing a machine.

Each player gets a random client ID generated on first visit and stored in localStorage. There are no accounts, no passwords, no email addresses. When a daily game ends we call a Netlify Function with the score, the session token, and the date. The function verifies the session, checks the score against a server-side cap, and upserts the row. The unique constraint on (client_id, challenge_date, mode) means replaying the daily can only improve your score, never submit a duplicate.

Score validation is the part that takes the most care. We replay the submitted events server-side — the sequence of gate hits — and reject any submission where the reconstructed score does not match the claimed score, or where the event sequence is physically impossible (too many coins hit the same gate in too short a time). It does not catch every cheat, but it raises the bar enough that the leaderboard stays meaningful.

The leaderboard page itself is a standalone HTML file that fetches from the same Netlify Function. It supports three game modes, date navigation, pagination, and deep-linking to a specific rank — all from a single static page with no framework. Sprint mode required a custom Supabase RPC because PostgREST cannot express "sort completions by time ascending, then DNFs by score descending" in a single query without a stored function.

Cabinet Materials Without Files

Technical

We wanted the cabinet to look like a physical object — wood grain on the frame, brushed steel on the coin tray, a glass reflection over the playfield — without shipping texture image files. Everything is drawn at runtime on an offscreen canvas and used as a Phaser texture.

The wood grain uses fractional Brownian motion: several octaves of smooth noise summed with decreasing amplitude, then warped with a second noise pass to break up the regularity. On top of that we draw individual grain lines, five procedurally placed knots with halo rings, a gloss overlay, bevel edge lighting, and a corner vignette. It sounds like a lot of layers, but each one is simple — the complexity comes from how they interact.

The glass reflection is a separate transparent layer rendered above everything else. Two blurred diagonal streaks, a top-left corner glare, a bottom-right ambient bloom, and three smudge ellipses are composited using the canvas globalCompositeOperation. The whole layer is masked to the playfield polygon so the reflection only appears where the glass would be. On slower devices the glass layer is skipped entirely — we check navigator.hardwareConcurrency at startup and set a detail level accordingly.

The coin tray uses anisotropic horizontal grain — fine parallel lines with slight random offsets — plus a curved-tray tone gradient, two specular hotspots, and 54 high-frequency scratch lines rendered at low opacity. Getting the hotspot placement right was the fiddly part: too centred and it looks like a sphere, too far to one side and the tray reads as tilted. The bevel edge is a final stroke pass that ties the tray into the surrounding cabinet frame.

Why Coins Feel Weightless — and How We Fixed It

Technical

Something felt off about the coin physics for a long time and we could not quite name it. The coin would leave the launcher, arc across the playfield, and arrive at the back wall at basically full speed. In the physical Ray T6 the coin is squeezed between the glass front and the back wall as it travels — that pressure creates continuous friction on both axes. Our simulation had no equivalent. The coin was flying through empty space.

The fix is a per-frame velocity damping pass that runs on every in-flight coin after the physics step. Horizontal velocity is multiplied by 0.992 each frame, vertical by 0.997. Those numbers look small but they compound: at 60 fps, 0.99260 ≈ 0.62, meaning a hard horizontal flick loses about 38% of its speed per second. Vertical movement — which is mostly gravity-driven and much slower — loses only around 17% per second so it does not feel artificially dragged downward.

We also added a zero-snap threshold: once horizontal velocity drops below 0.02 m/s or vertical below 0.0005 m/s it is clamped to zero. Without this, the damping causes an asymptotic crawl — the coin technically never stops moving, which breaks the resting-contact detection in Box2D and causes micro-jitter in the columns.

Bigger Score Popups

UX

The numbers that float up when you hit a gate were a little hard to read at a glance. All score popups are now 25% larger — regular gate hits go from 18 to 23px, big wins (gate 10, wild port) from 24 to 30px, and the combo multiplier from 15 to 19px.

Personal Score History in the Win Screen

UX

Personal bests are now tracked separately for each mode (Classic, Sprint, Blitz) and each context (daily challenge vs free play) — six values in total. The win overlay shows the relevant best for the mode you just played, with Sprint displaying a formatted best time rather than a score. The share card always reports your daily classic best and labels it as such. The personal stats overlay now shows a full bests table in place of the single "High Score" block.

After finishing a daily classic game, the win overlay now shows a sparkline of your last ten scores. A thin polyline connects the data points and today's score is highlighted in gold, so you can see at a glance whether this run was a new high, a recovery, or right on trend.

Scores are stored locally and are never shared. The chart only appears once you have played at least two daily classic games.

Tutorial Auto-Shows for New Players

UX

First-time visitors now see the tutorial automatically — the welcome screen is skipped and the tutorial opens right away so new players are not dropped into the game without any guidance. Players who arrive via a direct mode link (e.g., a PWA shortcut) bypass the tutorial as before.

The "How to Play" button on the welcome screen has been made more prominent: it moved from a small link in the bottom-right corner to a clearly styled, centred button at the bottom of the panel.

The tutorial has grown from three steps to four. The new R Columns step explains that hitting an R gate adds a coin to that side's R-column, and that 5 coins pay out once the column fills to 7. A pulsing red spotlight covers both R gates and their full columns below so players can see exactly what they're managing.

Touch Launcher Moved to the DOM

MOBILE FIX

The touch launch button is now a proper DOM element fixed to the lower-right corner of the screen rather than a circle drawn inside the Phaser canvas. It sits at a consistent position regardless of canvas scaling, and is styled with CSS transitions for the pressed and invalid-aim states.

Two positioning bugs have been fixed along the way. On Android phones with gesture navigation the button was clipped behind the gesture strip at the bottom of the screen — Chrome positions fixed elements relative to the layout viewport, which includes that strip. The fix reads window.visualViewport.height and adjusts the bottom offset at runtime so the button always sits above the visible edge. On wider touch devices where the sidebar is also shown, the New Game and Mute buttons now slide up to clear the launch button rather than sitting behind it.

Wood, Glass, and Steel

VISUALS

Three flat surfaces in the cabinet have been replaced with procedurally generated textures.

The wooden frame now has a varnished-walnut finish: vertical grain with noise-based warp, five knots, a diagonal gloss overlay, bevel lighting, and a corner vignette. The coin tray is brushed steel — anisotropic horizontal grain, a curved tone gradient, two specular hotspots, and fine scratch lines. A glass layer now sits in front of the entire playfield: two diagonal reflection streaks, a top-left corner glare, fresnel edges, and faint smudge ellipses, all at around 5–8% total opacity — invisible to look for, but immediately obvious when switched off.

0-20 Port in Daily Challenges

GAMEPLAY

The 0-20 port now appears in roughly one in three daily challenges, regardless of whether you have unlocked it in free play.

Share links generated from a daily that includes the 0-20 port correctly preserve the port state, so anyone replaying your link faces the same conditions.

The 0-20 Port Now Works Like the Real Machine

GAMEPLAY

The 0-20 port has been reworked to match how the physical Ray T6 actually worked.

Previously the gate paid out a random amount between 1 and 20 coins each time you hit it. That was a misunderstanding of the original mechanic. On the real machine the gate has an internal fill counter. Every hit adds one coin to it. When the count reaches 20, the gate pays out all 20 and resets to zero.

In this version the counter starts at a random position between 0 and 19 at the beginning of each round, so you never know how many hits away the payout is when the gate first unlocks. That uncertainty — combined with having to hit the 10 gate ten times just to activate it — makes the 0-20 port a proper long-game objective rather than a random bonus.

The payout now triggers a noticeably larger effect than a regular big win: a full-screen flash, an expanding ring, and a heavier vibration pattern.

Faster Frames with Many Coins

PERFORMANCE

Two changes that make a noticeable difference when many coins are in motion at once.

Field coins — the ones resting in columns — are static. They never move between frames, so syncing their sprite positions from the physics engine on every frame was pointless. The per-frame sync now only runs for coins that are actually in flight. As the columns fill up over a round, this loop shrinks from iterating 60+ coins down to just the 1–5 that are airborne.

The physics engine was also allowed to run up to five catch-up steps on a slow frame, which made slow frames even slower. That limit is now three, so a brief hiccup doesn't cascade into a longer one.

Trail ghost images are now pre-allocated and recycled instead of being created and discarded each frame, reducing garbage collection pressure during heavy play.

Performance Pass

PERFORMANCE

A round of under-the-hood work to make the game load faster and run more smoothly.

The HUD updates more efficiently now — the score bar, coin counter, and sidebar no longer do unnecessary work on every frame when nothing has changed.

Sound effects are 85% smaller on the wire, so the game loads noticeably faster on a slow connection. The sounds themselves are unchanged.

Opening the stats overlay repeatedly no longer fires redundant network requests.

HUD Bar Polish and Rem Units

UI

The mobile HUD bar (score and coin counter in portrait mode) is now 56 px tall instead of 46 px. The extra space prevents the bar from feeling cramped, and gives text room to wrap without clipping. When a value does wrap to a second line, the gap between lines is 2 px wider than the browser default thanks to an explicit line-height.

All font sizes in the DOM layer — the HUD bar, menu popup, and desktop sidebar — have been converted from px to rem. At the default browser font size they render identically, but users who have set a larger base font in their browser or OS accessibility settings now get proportionally larger UI elements for free.

Easier to Read on Mobile

UI

Several players reported that text was hard to read on phone screens. After an audit of every text element in the game, two categories of issues showed up: CSS font sizes that were too small in the DOM HUD bar and menu, and canvas overlay text that didn't scale up on narrow screens the way the welcome screen and win overlay already did.

The DOM HUD score and coin counter (the bar at the top in portrait mode) went from 9 px to 10 px. Menu headers, items, and sub-labels each went up one step. The desktop sidebar labels and values got a similar bump. None of these change layout — the bar height, padding, and flex sizing all stay the same, the text just fills in a bit more.

On the canvas side, the Tutorial overlay, Legal overlay, and Lifetime Stats overlay now apply the same 1.25× font scale that the Welcome and Win overlays have used since May 3. Body text that was 13 px on desktop renders at 16 px in phone portrait; the tutorial panel is also slightly taller to give the larger text room to breathe. Block values in the stats overlay scale down slightly on mobile (40 → 32 px) so longer numbers don't overflow the grid cells.

Blitz Gets a Coin Limit — and the App Becomes Installable

GAMEPLAYPWA

Blitz now has a 40-coin ceiling alongside the 20-second timer. The game ends whichever comes first — coins or clock. Previously Blitz gave you unlimited coins for 20 seconds, which made it too easy to keep firing without thinking. The coin limit adds a resource constraint that sits alongside the time pressure: you have to be selective, not just fast. The HUD now shows both countdowns at the same time so you always know where you stand on each.

On the PWA side, Knipsekasse is now properly set up for installation on desktop and mobile. The web manifest has been fleshed out with a full icon set (16 px through 1024 px plus an SVG), app shortcuts for jumping straight into Daily Classic, Sprint, or Blitz from the home screen jumplist, screenshots for the install prompt, and correct metadata including language, text direction, scope, and app category. The new logo — coin in flight above the gate strip — replaces the old placeholder icon everywhere including the favicon.

Nickname filtering has been added: names are checked against a profanity list before being saved locally and again on the server before hitting the leaderboard. Flagged names are rejected with a prompt to choose something else; scores submitted through modified clients fall back to Anonymous.

Three Ways to Play — Classic, Sprint, and Blitz

GAMEPLAY

Knipsekassen now has three distinct game modes, each available as a daily challenge or as free play. Classic is the original — 50 coins, chase the highest score. The two new modes change the rules entirely.

Sprint starts you with 15 coins and a target of 50. Every coin you score through a gate refills your bank by that gate's value, so the game is really about efficiency: can you keep the bank alive long enough to reach 50? Miss too many and the bank drains to zero — DNF. The HUD shows elapsed time (to the hundredth of a second) and your current bank balance as "x of 50", so you always know exactly where you stand. Completing the run stops the clock and posts your time to the Sprint leaderboard, sorted fastest first.

Blitz is the opposite pressure. You have 20 seconds and 40 coins — fire as fast as you can and pile up as many points as possible before either runs out. The timer ticks down in hundredths, goes red in the final five seconds, and both countdowns are shown in the HUD so you always know which constraint is tighter.

The menu now lists all six combinations (three daily, three free-play) and marks the active mode. The New Game button in the HUD restarts whatever mode you're currently playing — no more accidentally dropping back to Classic. Daily Sprint and Daily Blitz each have their own leaderboard tab on the leaderboard page, with Sprint sorted by completion time.

This Log

UI

The version history that used to live inside the game has been replaced with this page. Instead of a scrollable list of one-liners, each update now gets room to explain what actually changed and why it matters.

The version number in the bottom corner of the game links here, and there's a shortcut in the menu as well.

New HUD — Sidebar on Desktop, Dark Bar on Mobile

UI

The way the game presents information while you play has been completely redesigned. On wide screens a slim panel now sits to the right of the playing field, showing your score, remaining coins, a daily challenge badge and quick access to a new game and mute. The game board itself is left uncluttered.

On phones the top bar takes on the same dark cabinet palette as the rest of the game, finally making everything feel like it belongs together.

Combo multipliers no longer live in the HUD. When you land back-to-back gate entries the multiplier now pops up directly above the gate you just scored through — colour-coded green through gold to red as it climbs — then drifts upward and fades. It puts the information exactly where your eye already is.

The in-game menu also moved to a proper overlay panel with a Settings sub-page, direct links to the Leaderboard and May Challenge, and cleaner typography throughout.

Pegs That Actually Do Something

GAMEPLAY

The pegs inside each gate are the single biggest factor in whether a coin drops straight through or gets deflected away. This update replaces the old freeform placement with a deliberate system of three configurations: angled left, angled right, or straight down the middle. That alone makes each gate layout more readable at a glance.

On top of that, each peg now has a tension setting — ten levels from loose to stiff. A loose peg barely nudges a coin; a stiff one can send it flying. The combination of position and tension gives each gate a distinct personality, and you can see exactly how each is configured from the peg channel lines drawn inside the gate.

The daily challenge seed now captures every peg position and tension value, so the layout is identical for every player on a given day. Shared links carry the same information, so replays are exact.

Better Readability on Mobile

UI

The welcome screen and end-of-round overlay now use larger, better-proportioned text on phones. Previously both screens defaulted to desktop-sized text regardless of screen size. Now the panels scale to make full use of the available space, making stats and scores far easier to read after a run.

The win overlay now also shows your rank against everyone else who played the daily challenge that day, with a direct link through to the full leaderboard.

Aim Guide Overhaul

GAMEPLAY

The aiming experience got a significant upgrade. The guide is now a row of fading dashed dots with an arrowhead at the tip — much easier to track against a busy field than the old solid line. The power indicator switches from a plain bar to an eight-segment display that shifts from green through gold to red as you pull back, making it immediately obvious how hard the shot will be.

One small but important fix: power now resets to its default after every shot. Previously, if you locked in a heavy pull and fired, the next shot would start from that same power — leading to unintentional maximum-force shots. Now each coin always starts fresh.

Combo System

GAMEPLAY

Chain consecutive gate entries and a combo multiplier starts climbing. Each hit in the chain is announced with a tone that rises in pitch, and the counter shows how many you've strung together. Land a coin in the field instead of a gate and the chain resets. Your best combo of the round is shown on the win overlay.

The COINS counter now starts at 50 and counts down as you fire, making your remaining shots immediately clear from the moment you load the game.

The R gate columns also got a seeding fix. Both R columns now start with a coin count that varies per free game and is fixed for the daily challenge, rather than always starting empty.

Fewer Stuck Coins

FIX

Coins occasionally settled into positions where they stopped moving entirely, stalling the field and blocking later shots. This update makes it considerably less likely for coins to get wedged, keeping things moving and the game from grinding to a halt mid-round.

Global Daily Leaderboard

FEATURE

Every score from the daily challenge now feeds into a live leaderboard at knipsekassen.no/leaderboard. You can see the top 25 players for any date, page forward to find your rank, or jump straight to a specific number. After a daily game the win overlay links directly to the page where your result appears.

Several physics issues were fixed in this session too. A bug that left invisible obstacles in gates after a coin passed through is gone. Coins can no longer slip through the gap between the outermost gates and the cabinet walls.

Daily Streak, Gold Cabinet and Install Support

FEATURE

Play the daily challenge two days running and a streak starts counting on the welcome screen. Keep it going for five days while also scoring 10 on a gate in any of those sessions and the Gold Cabinet unlocks — a full warm amber colour scheme as a reward for consistent play. Miss a day and the streak resets.

The game can now be installed as an app directly from the browser on both phones and desktops. Once installed it runs full-screen without browser chrome, and the latest version loads even when your connection drops.

The Big One

MAJOR UPDATE

A lot arrived in a single day. Here's a rundown:

Gate Labels and Stability

POLISH

The gate value labels were reformatted. 2 becomes 2:00, 3 becomes 3:00, 10 becomes 10:00 — reading more like a classic arcade scoring display.

Coins were also less likely to get stuck in this update, continuing the ongoing tuning work that started in February.

Xbox Controller Support

FEATURE

The game now works with a standard Xbox controller. Either stick or the d-pad controls aim, and power is set the same way. Press A to fire. Everything that works with a keyboard also works with a pad. If you have a controller plugged in, it just works.

Cabinet Visual Polish

POLISH

The green cabinet panels were darkened and given a subtle metallic sheen, bringing them closer to the look of a real arcade cabinet. The centre guide ellipse was redesigned, the bottom panel was split into two trapezoidal pieces flanking the coin exit channel, and the column dividers were lengthened and realigned.

These are all purely cosmetic — the physics didn't change — but the board reads more cleanly as a result.

Input Precision and Aim Guards

GAMEPLAY

The aim guide became a visual ray with a power bar, replacing the old text readout that showed angle and power as numbers. Keyboard aiming is now clamped to the valid launch arc — aiming into the cabinet wall is no longer possible. If you try to aim in a direction that can't result in a valid shot, the guide turns red and the shot won't fire.

Keyboard shot jitter was cut in half, making precision shots more consistent. The maximum launch force was also reduced slightly so coins travel at a more natural pace.

Win Overlay, Sound and Lifetime Stats

FEATURE

The first proper end-of-round screen arrived. Your total score, a tier callout based on how well you did, and a large Play Again button. Before this update the round just ended silently and you had to start a new game manually.

Win sounds now scale with your score: higher tiers get longer, more elaborate audio sequences. A mute button was added to the HUD.

Lifetime stats landed in the same session. Every round you play contributes to a running total: games played, coins fired, gates hit by port. The stats overlay accessible from the menu shows all of it and lets you reset if you want a clean slate.

Mobile Controls and Touch Polish

FEATURE

The first pass at proper mobile support. The touch launch button was made larger and repositioned so it sits comfortably under your thumb. In portrait mode the HUD and menu button moved above the canvas into the black letterbox area, keeping them accessible without covering the board.

Aim and power inputs were unified across mouse, touch and keyboard so they all behave consistently. Previous builds had subtle differences in how each input method calculated the shot vector — those were ironed out here.