A TUI (Charm Wish) ww1 dog fighting game of sorts.
  • Go 97.3%
  • Just 2.2%
  • Shell 0.3%
  • Dockerfile 0.2%
Find a file
Snorre Magnus Davøen 99cdef2bbb
tweak: increase ammo regen rate from 2.0s to 1.5s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 22:30:33 +01:00
.claude Refactor Render into composable methods on renderCtx 2026-03-10 23:26:02 +01:00
benchmarks bench: run benchmarks for e77283bb 2026-03-14 22:10:10 +01:00
internal/game tweak: increase ammo regen rate from 2.0s to 1.5s 2026-03-14 22:30:33 +01:00
.dockerignore feat: initial game implementation of aces 2026-03-08 23:56:56 +01:00
.gitignore feat: initial game implementation of aces 2026-03-08 23:56:56 +01:00
Dockerfile Fix color rendering in Docker, add justfile for builds 2026-03-09 00:37:40 +01:00
go.mod feat: add goose migrations for highscore DB 2026-03-14 22:26:11 +01:00
go.sum feat: add goose migrations for highscore DB 2026-03-14 22:26:11 +01:00
justfile Add benchmark performance tracking infrastructure 2026-03-12 23:24:52 +01:00
main.go feat: add goose migrations for highscore DB 2026-03-14 22:26:11 +01:00
README.md Add benchmark performance tracking infrastructure 2026-03-12 23:24:52 +01:00

ACES

A multiplayer WWI-themed dogfighting game played entirely in the terminal over SSH.

    _    ____ _____ ____
   / \  / ___| ____/ ___|
  / _ \| |   |  _| \___ \
 / ___ \ |___| |___ ___) |
/_/   \_\____|_____|____/

Connect to a server, pick a callsign, and engage in side-scrolling aerial combat with other players. No client installation required — just SSH.

ssh your-server.com

Gameplay

You fly a biplane in a horizontally-wrapping world filled with floating airships. Shoot down other players, collect power-ups, and climb the scoreboard.

Controls

Key Action
Left / Right Change direction
Up / Down Move vertically
Space Shoot
Double-tap Left/Right Activate boost
W Drop mine
Q Quit

Combat

  • Bullets travel horizontally in your facing direction
  • Hitting another player scores a point; they respawn after 3 seconds
  • Crashing into an airship destroys your plane (shields absorb one hit)
  • Head-on collisions kill both players

Power-ups

Power-ups spawn randomly throughout the world:

Icon Type Effect
D Double Shot Fires two parallel bullets (10s)
S Scatter Shot Fires a 3-bullet spread (10s)
M Mine Pack Grants 3 mine charges
O Shield Absorbs one hit (10s)

Mines

  • Drop mines behind your plane with W
  • Mines are triggered by proximity (any non-owner player within 1 cell)
  • The blast radius is 4 cells and damages everyone caught in it, including the owner (friendly fire)
  • You cannot trigger your own mines by flying over them

Boost

  • Double-tap your current direction to activate a speed boost (3x speed)
  • Boost consumes fuel that recharges over time
  • The HUD shows your current fuel level

Spawn Protection

You get 2 seconds of invulnerability after spawning, shown by a blinking effect. During this time you cannot be damaged by bullets, mines, collisions, or airships.

World

  • The world is 1200 cells wide and wraps horizontally
  • 30-45 floating airships drift across the sky as obstacles and cover
  • A wrap seam marker shows where the world loops
  • Ground and ceiling boundaries constrain vertical movement

HUD

The top bar shows:

  • Score — your current kill count
  • Ammo — regenerates over time (max 10)
  • Boost fuel — shows remaining boost capacity
  • Active weapon — if you have a power-up weapon, with time remaining
  • Shield timer — if shielded
  • Mine count — available mine charges
  • Player count — number of connected players

The sidebar shows a live scoreboard of all players.

Running Locally

Requires Go 1.26+.

go run .

The server starts on port 2222 by default. Connect with:

ssh localhost -p 2222

Environment Variables

Variable Default Description
ACES_HOST 0.0.0.0 Listen address
ACES_PORT 2222 Listen port
ACES_HOST_KEY .ssh/id_ed25519 Path to SSH host key

Deployment

Docker

docker build -t aces .
docker run -d --name aces --restart unless-stopped \
  -p 22:22 \
  -v aces-data:/data \
  aces

The container runs on port 22 by default so players can connect with just ssh your-server.com.

The /data volume persists:

  • SSH host key (.ssh/id_ed25519) — generated on first run; keeps the key stable across redeployments so players don't get host key warnings
  • Highscore database (aces.db) — SQLite file tracking top scores

VM Considerations

  • If your VM's own sshd runs on port 22, move it to another port in /etc/ssh/sshd_config before starting the container
  • Ensure port 22 is open in your firewall / security group
  • The game accepts all SSH connections without authentication — this is by design for a public game

Architecture

Built with:

Each SSH connection gets its own Bubble Tea program. A shared world singleton runs the game loop at 20 FPS (50ms ticks), broadcasting state to all connected players via channels. Input from each player is forwarded to the world under a write lock, and rendering reads state under a read lock.

AI bots (Maverick, Goose) join automatically to keep the game interesting when few players are online.

Benchmarks

Performance is tracked across commits for the hot-path functions (Render and Tick). See benchmarks/BENCHMARKS.md for trend charts.

just bench              # run benchmarks, print results
just bench-save         # run (count=6), save median to CSV, update charts
just bench-compare REF  # compare current against a saved commit via benchstat
just bench-history      # list saved benchmark commits

License

MIT