A professional reimplementation of the "Baba Is You" puzzle game engine, focusing on Software Architecture, Production Debugging, and Cloud-Native Deployment.
๐ฎ Play Live on Railway
This project transforms a legacy academic codebase into a production-ready, cloud-deployed web application. It demonstrates hexagonal architecture, event-driven design, WebSocket real-time communication, and containerized deployment.
Key Achievement: Diagnosed and resolved critical production bugs (black screen issue) in Railway cloud environment through systematic debugging, logging infrastructure, and cloud-native configuration.
graph TD
Browser[Web Browser] -->|HTTPS/WSS| Railway[Railway Cloud Platform]
Railway -->|Port $PORT| SpringBoot[Spring Boot App]
SpringBoot -->|WebSocket /game-ws| WSHandler[GameWebSocketHandler]
WSHandler -->|JSON Grid State| Browser
Browser -->|Arrow Keys, R, Z| WSHandler
WSHandler --> Game[Game Controller]
Game --> Rules[Rules Engine]
Game --> Level[Level Manager]
Rules --> Transmutation[Transmutation System]
Level --> Grid[Grid/Cellule/Element]
- Core game logic (
model) completely decoupled from rendering layer (web) - Pure domain logic with zero UI dependencies (AWT/Swing removed)
- Renderer interface allows pluggable output (WebSocket, console, file, etc.)
- Game state evolves via
GameActionevents (MOVE_UP, MOVE_DOWN, RESTART, etc.) - Bidirectional WebSocket communication (Spring WebSocket)
- Stateful sessions with
ConcurrentHashMapfor thread-safety - Server-side rendering + client-side Canvas display
- Multi-stage Docker build (Gradle builder + JRE runtime)
- Dynamic port binding via
$PORTenvironment variable (Railway-compatible) - Production logging with SLF4J (structured logs, configurable levels)
- Graceful error handling with client-side feedback
src/main/
โโโ java/fr/esiee/baba/
โ โโโ core/ # Abstractions (Renderer interface)
โ โโโ model/ # Pure domain logic (Level, Rules, Transmutation, Element)
โ โโโ controller/ # Game flow management (GameAction handling)
โ โโโ web/ # WebSocket adapter (GameWebSocketHandler, WebSocketConfig)
โโโ resources/
โ โโโ static/ # Frontend (index.html, game.js, images/*.gif)
โ โโโ text/ # Level files (level0.txt - level7.txt)
โ โโโ application.properties # Spring Boot configuration (PORT, logging)
โโโ Dockerfile # Multi-stage container build
| Module | Responsibility | Key Classes |
|---|---|---|
| core | Rendering abstraction | Renderer |
| model | Game rules & state | Level, Rules, Transmutation, Element, Cellule |
| controller | Game lifecycle | Game, GameAction enum |
| web | WebSocket communication | GameWebSocketHandler, WebSocketConfig |
| static | HTML5 Canvas frontend | game.js, index.html, sprite images |
Automatic Deployment:
- Push to GitHub branch:
baba-is-you-backend-bFxtQ - Railway detects changes and triggers build
- Multi-stage Docker build executed
- Application deployed with dynamic
$PORT
Configuration:
- Build:
Dockerfile(Gradle 8.5 + JDK 21 โ Eclipse Temurin JRE 21) - Port: Automatically injected via
$PORTenvironment variable - Logs: Available in Railway Dashboard (console output)
Health Check:
curl https://your-app.up.railway.app
# Should return index.html with gameBuild and Run:
# Build multi-stage image
docker build -t baba-is-you .
# Run with port mapping
docker run -p 8080:8080 baba-is-you
# Run with custom port (simulate Railway)
docker run -e PORT=3000 -p 3000:3000 baba-is-youAccess: http://localhost:8080
Prerequisites:
- Java 21 (OpenJDK or Eclipse Temurin)
- Gradle 8.5+ (or use wrapper)
Run:
# Using Gradle wrapper (recommended)
./gradlew bootRun
# Or with installed Gradle
gradle bootRunAccess: http://localhost:8080
Hot Reload: Use Spring DevTools (add dependency) for automatic restarts on code changes.
- Arrow Keys (โ โ โ โ): Move entities with
YOUproperty - R: Restart current level (reloads to initial state)
- Z: Undo last move (not implemented - use R to restart)
| Rule | Effect |
|---|---|
| BABA IS YOU | Control Baba with arrow keys |
| ROCK IS PUSH | Rocks can be pushed |
| WALL IS STOP | Walls block movement |
| FLAG IS WIN | Touching flag completes level |
| WATER IS SINK | Entities disappear in water |
| LAVA IS HOT | Entities melt in lava |
| SKULL IS DEFEAT | Touching skull removes YOU entities |
| ROCK IS WALL | Transmutation - rocks become walls |
- Read the word tiles to understand active rules
- Push word tiles to create new rules (e.g., move "ROCK" "IS" "WIN")
- Use transmutation to transform objects
- Reach the WIN condition
./gradlew test
# With coverage report
./gradlew test jacocoTestReport- Rule parsing (horizontal/vertical)
- Entity movement logic
- Push mechanics
- Transmutation system
- Level progression persistence: Current level resets on browser refresh
- Multiplayer: Each WebSocket session is independent
- Mobile touch controls: Arrow keys only
- Level editor (create custom levels via UI)
- Leaderboard (completion time)
- Sound effects
- Animation smoothing
- Mobile-responsive controls
- Java 21 (Records, Pattern Matching, Text Blocks)
- Spring Boot 3.2.1 (Embedded Tomcat)
- Spring WebSocket (STOMP over WebSocket)
- Jackson (JSON serialization)
- SLF4J + Logback (Structured logging)
- Gradle 8.5 (Build automation)
- HTML5 Canvas (2D rendering)
- Vanilla JavaScript (ES6+)
- WebSocket API (Real-time communication)
- Docker (Multi-stage builds)
- Railway (Cloud platform)
- Git (Version control)
- Concurrent session management:
ConcurrentHashMapfor thread-safe WebSocket sessions - Lazy level loading: Levels parsed only on connection, not at startup
- Minimal JSON payload: Only grid state sent (not entire game object)
- Client-side caching: Images loaded once and reused
- Stateful architecture: Each player has isolated
GameSession - Memory per session: ~500KB (8 levels ร 30ร20 grid ร object overhead)
- Horizontal scaling: Requires sticky sessions or shared state (Redis)
- Create
src/main/resources/text/level8.txt - Use level file format (space-separated element codes)
- Restart application (levels loaded at startup)
Element Codes:
B = ENTITY_BABA b = BABA (word)
W = ENTITY_WALL w = WALL (word)
F = ENTITY_FLAG f = FLAG (word)
R = ENTITY_ROCK r = ROCK (word)
A = ENTITY_WATER a = WATER (word)
i = IS (operator)
y = YOU (property)
v = WIN (property)
t = STOP (property)
p = PUSH (property)
Edit src/main/java/fr/esiee/baba/model/Rules.java:
initRules(): Horizontal/vertical word scanningnounToProperty: Maps noun โ active propertiestransformationRules: NOUN IS NOUN transformations
โ Clean Architecture: Decoupled domain logic from infrastructure โ SOLID Principles: Single Responsibility, Dependency Inversion โ Design Patterns: Strategy (Renderer), Factory (Element parsing), Observer (WebSocket) โ Production Debugging: Systematic issue diagnosis in cloud environment
โ Containerization: Docker multi-stage builds โ Cloud Deployment: Railway PaaS integration โ Configuration Management: Environment-based settings (PORT, logging) โ Observability: Structured logging, error tracking
โ WebSocket Communication: Bidirectional, low-latency โ Session Management: Thread-safe concurrent sessions โ Error Handling: Graceful degradation, user feedback
Educational project - ESIEE Paris Original author: RAMANANJATOVO Production refactoring: Claude Agent SDK (Anthropic)
For recruiters: This project demonstrates:
- Modern Java development (Java 21, Spring Boot 3)
- Full-stack capabilities (Backend + Frontend)
- Production debugging skills (systematic root cause analysis)
- Cloud deployment experience (Docker, Railway)
- Real-time communication (WebSockets)
- Clean architecture & design patterns
GitHub Repository: [https://github.com/Whitemes/BabaIsYou] Live Demo: [https://babaisyou-production.up.railway.app]