← Back to projects

jack7

Designed and built a real-time multiplayer iOS card game from scratch — authoritative Go server, polished SwiftUI client, CI/CD to production.

RoleSolo founder & engineer
StatusApp Store
StackSwiftUI · Go · WebSocket · Docker
SwiftUI·Go·WebSocket·Game Development·Docker·Coolify

Why this project exists

jack7 is a multiplayer shedding card game — the UK "BlackJack" variant of the Crazy Eights / Switch family. I grew up playing it with family and friends, and the existing digital versions were either dead, riddled with ads, or got the rules wrong. I wanted to build the definitive version: correct rules, polished feel, and a design that respects the tabletop experience.

It's also a playground for game server architecture, real-time networking, and native iOS development — skills I've been developing alongside my day job building enterprise mobile and web platforms.

What I built

Authoritative Go game server

The server owns all game logic. Clients are thin viewers — they send intents and render state. This prevents cheating, keeps a single source of truth, and makes it easy to add new clients later.

The game engine implements the full UK BlackJack rule set:

  • Power cards: 2s (pickup 2), 8s (skip), Black Jacks (pickup 7), Red Jacks (cancel), Queens (naked queen), Kings (reverse), Aces (suit change), Jokers (wild with declared identity)
  • Runs: chain multiple cards per turn by rank-match → sequence → pivot
  • Stacking: pickup cards stack (2+2=4, 2+Black Jack=9), skips stack, mid-run effect swallowing when you play past a power card
  • Cards-call state machine: 3-state (None/Pending/Armed) with off-turn calling, idempotent re-calls, and cycle-forward — prevents tap-spam desyncs and enables legal win windows
  • Per-game audit log: every action captured server-side with typed effect tags, rendered in the iOS app via GameLogView

The server runs on Hetzner via Coolify, deployed automatically on every push to main through GitHub Actions → GHCR → Coolify webhook. It serves the game over WebSocket and the public website (landing, privacy, terms, roadmap) from the same Go binary — all pages rendered from embedded markdown.

Infrastructure includes an admin dashboard with live Chart.js metrics, structured JSON logging (slog), stats history with JSONL persistence, and a protocol-version handshake that gates force-upgrade for incompatible clients.

Polished SwiftUI iOS app

The iOS app is native SwiftUI with an MVVM architecture. It's a thin client — no game logic duplicated, just state rendering and intent sending.

Key features:

  • Event-queue architecture: separates logical game state from visual state for smooth, independent animations
  • Card-flight animations: cards animate from hand to discard pile with proper z-ordering
  • Sound design: select, place, stacked pickup, deck shuffle, riffle on hand reorder
  • Haptics: select, place, heavy power thump, per-card staggered pickup, rigid skip, medium reverse, success on win
  • Drag-to-reorder: rearrange your hand with a riffle sound effect
  • Strict Joker UI: identity picker, resolution pill, masked power burst animation
  • Force-upgrade: version-gated upgrade screen + recommended-update banner, driven by server protocol version
  • Reconnection: exponential backoff with state rebuild on reconnect, "Reconnecting…" overlay
  • Accessibility: VoiceOver labels ("Seven of Hearts"), Dynamic Type, 44pt touch targets, colorblind-friendly suit differentiation

The design system is a custom felt-and-gold palette (J7Colours, J7Cards, J7Components, J7Ornaments) inspired by the green baize of a card table.

Virtual lobby bots

A host can add or remove AI bot players in the lobby, letting you fill a table without waiting for human opponents. The bot decision engine makes legal plays respecting the full rules — it understands runs, stacking, Joker identity, and naked queens.

CI/CD pipeline

Every push to main that touches server/** triggers:

  1. go test ./...
  2. go build
  3. Multi-stage Docker build → ~10 MB final image
  4. Push to ghcr.io/ambacelar/jack7/server:latest
  5. Coolify webhook triggers pull + redeploy

What's next

I've designed a 1,268-line spec for ranked matchmaking with ELO/MMR, Apple Sign-In, StoreKit 2 subscription validation (com.jack7.ranked.yearly), PostgreSQL persistence, leaderboards, and player profiles. This is the monetisation layer — ranked play as a premium feature — but it waits until the casual game has enough traction and polish to justify the investment.

Links