A classic Squash game developed in Go (TinyGO) and compiled to WebAssembly (WASM), running directly in the browser without any plugins.
๐พ For Players:
๐จโ๐ป For Developers:
๐๏ธ For Software Engineers:
- ๐ Technical Data - Architecture, Design Patterns and Stack
Squash is an arcade game where you control a paddle and must bounce the ball against the wall, preventing it from escaping through the left side. With each successful hit, you earn points and the game becomes progressively more challenging.
- Bounce the ball with the paddle
- Prevent the ball from escaping through the left side
- Each hit earns you points (10 points)
- Every 100 points, you advance to the next level and the ball gets faster
- You start with 3 lives (default)
Note: The game requires a mouse or stylus (pen) for tablets. Touch controls are not supported.
- Move paddle: Move the mouse (or stylus) vertically
- Start game: Left click
- Pause: Right click
- Restart: Left click (on Game Over screen)
You can customize the game through query parameters:
http://localhost:8080?debug=true&lives=5&level=10&boost=0.8&ballsize=0.7&fps=60
| Parameter | Type | Range | Description |
|---|---|---|---|
debug |
boolean | true/false | Enables debug mode with information |
lives |
int | 1 - 99 | Initial number of lives |
level |
int | 0 - 50 | Starting game level |
boost |
float | 0.0 - 1.0 | Speed increment per level |
ballsize |
float | 0.0 - 1.0 | Ball size scale |
fps |
int | 30 or 60 | Frames per second (update rate) |
๐ฆ Prerequisites and Installation (click to expand)
Option 1: Local Execution
- Go 1.23+
- TinyGo (to compile to WASM)
Option 2: Docker Execution ๐ณ
- Docker installed
# Clone the repository
git clone https://github.com/psaraiva/squash.git
cd squashSimpler! No need to install Go or TinyGo.
# Build and run in a single command
make docker-deployAccess: http://localhost:8080
Available Docker commands:
make docker-build # Build Docker image
make docker-run # Run container
make docker-stop # Stop and remove container
make docker-clean # Remove container and imageRequires Go 1.23+ and TinyGo installed.
# Install dependencies
go mod download
# Build and start local server
make web-deploy-local
# Or run commands separately:
make web-build # Compile to WASM
make web-serve-start # Start HTTP serverAccess: http://localhost:8080
Cleanup:
make web-clean # Remove compiled files (local)๐งช Tests (click to expand)
# Run all tests with coverage
make go-test-all
# Run only unit tests
make go-test
# Run only WASM tests
make go-test-wasm
# Generate interface mocks
make go-mockCoverage: 100% of statements tested
For software engineers: This project demonstrates Clean Architecture and Hexagonal Architecture (Ports & Adapters) in Go with WebAssembly, 100% testable and extensible.
๐ฏ Technical Features (summary)
- ๐ Runs in the browser via WebAssembly
- ๐ฎ Control via mouse or stylus (does not support touch)
- ๐๏ธ Progressive level system with increasing difficulty
- ๐จ Clean and responsive interface
- ๐ Debug mode for developers
- โ๏ธ Customizable settings via query string
- โ 100% test coverage
๐ Technology Stack (click to expand)
- Go 1.23 - Main programming language
- TinyGo - Optimized compiler for WebAssembly
- WebAssembly (WASM) - Technology to run Go code in the browser
- JavaScript - Integration with browser APIs via
syscall/js
- Clean Architecture - Clear separation of layers (domain, ports, adapters)
- Hexagonal Architecture - Ports & Adapters pattern
- Dependency Injection - Interfaces for decoupling
- Strategy Pattern - Mouse input strategy
- Go Testing - Native testing framework
- Custom Mocks - Own implementation without external dependencies
- Table-Driven Tests - Go-recommended testing pattern
- TinyGo Test - WASM target compatible tests
- Make - Build and deployment automation
- Docker - Containerization with multi-stage build
- Go Modules - Dependency management
๐๏ธ Project Structure (click to expand)
squash/
โโโ cmd/ # Entry points (delivery interfaces)
โ โโโ wasm/ # WebAssembly implementation
โ โโโ main.go # Wire-up and initialization
โ โโโ index.html # HTML interface
โ
โโโ internal/ # Domain core (business logic)
โ โโโ app/ # Game engine and business rules
โ โ โโโ config.go # Configuration and default values
โ โ โโโ engine.go # Physics and game mechanics
โ โ โโโ game.go # State and game entities
โ โ
โ โโโ ports/ # Contracts/Interfaces
โ โโโ config.go # ConfigProvider interface
โ โโโ renderer.go # Renderer interface
โ โโโ mocks/ # Generated mocks
โ
โโโ pkg/ # Reusable code (infrastructure)
โ โโโ adapters/ # Port implementations
โ โโโ input/ # Input adapters
โ โ โโโ wasm/ # WASM config loader
โ โ โโโ web/ # UI and rendering
โ โโโ output/ # Output adapters
โ โโโ web/ # Canvas renderer
โ
โโโ bin/ # Compiled artifacts
โโโ web/ # WASM assets
๐ Architecture and Design Patterns (click to expand)
This project was developed following the principles of Clean Architecture and Hexagonal Architecture (Ports & Adapters), making the code highly testable, maintainable, and extensible for different platforms.
- Responsibility: Pure business logic, game rules, physics
- Files:
engine.go(physics and mechanics),game.go(state),config.go - Independent: Doesn't know infrastructure details (Web, CLI, etc)
- Testable: 100% testable without external dependencies
- Responsibility: Contracts/interfaces that the domain expects
- Interfaces:
ConfigProvider,Renderer - Dependency Inversion: Domain defines, adapters implement
- Responsibility: Concrete implementations of ports
- Input Adapters:
input/wasm/config_loader.go- Reads config from query stringinput/wasm/handler.go- Captures mouse eventsinput/web/ui.go- UI rendering logic
- Output Adapters:
output/web/canvas.go- Canvas 2D Rendereroutput/web/jscontext.go- Wrapper for syscall/js
- Interchangeable: Easy to swap implementations without affecting the core
- Responsibility: Composition (wire-up) and initialization
- Minimal logic: Only instantiates and connects components
The architecture allows easily creating new versions of the game for different platforms:
cmd/new/
โโโ main.go # entry point
pkg/adapters/
โโโ input/new/
โ โโโ config_loader.go # Reads config from flags/env
โ โโโ keyboard.go # Captures input
โโโ output/new/
โโโ renderer.go # rendering
Usage example:
go run cmd/new/main.goThe core (internal/app) remains 100% unchanged!
| Principle | Application in Project |
|---|---|
| SRP | Each package has a single responsibility |
| OCP | Extensible via new adapters without modifying the core |
| LSP | Renderer, ConfigProvider interfaces are substitutable |
| ISP | Small and focused interfaces |
| DIP | internal/app depends on abstractions (ports), not implementations |
- Hexagonal/Ports & Adapters: Isolated core, adapters connect infrastructure
- Dependency Injection: Components receive dependencies via constructor
- Strategy Pattern: Mouse input strategy
- Factory Pattern:
NewSquash(),NewRenderer(),NewConfigLoader() - Template Method:
Renderer.Render()with specific implementations
โ
Testability: Core testable without complex mocks (100% coverage)
โ
Maintainability: Changes isolated to specific layers
โ
Reusability: Game logic reusable on any platform
โ
Evolution: Easy to add features without breaking existing code
โ
Independence: Core doesn't depend on external frameworks
โ
Portability: Same core for Web, CLI, Mobile, Desktop
This project is open source and available under the MIT License.
Developed by @psaraiva
Have fun playing! ๐
