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! 🎉
