8.4 KiB
Break Escape: AI Coding Agent Instructions
Project Overview
Break Escape is a Rails Engine implementing a web-based educational game framework combining escape room mechanics with cyber-physical security learning. Players navigate 2D top-down environments (powered by Phaser.js), collect items, and solve security-themed mini-games aligned to the Cyber Security Body of Knowledge (CyBOK).
Deployment Modes
Break Escape always runs as a Rails Engine, but operates in two distinct modes:
- Standalone Mode: Local Rails instance with demo user support (development/testing)
- Mounted Mode: Integrated into parent Rails applications like Hacktivity for course management and secure assessment delivery
Server-Side Validation: Solution validation is enforced server-side. Client-side validation is for UX and gameplay only; solutions (such as passwords and pins) are verified against solutions on the backend before further game content such as rooms can be accessed.
Architecture
Rails Engine Integration
Break Escape is always a Rails Engine, operating in one of two modes:
Standalone Mode (Local Development):
- Runs as a self-contained Rails app with demo user support
- Uses
break_escape_demo_userstable for test players - Scenarios rendered on-demand with ERB template substitution (randomized passwords/PINs)
- State persisted in
break_escape_gamesJSONB column
Mounted Mode (Production/Hacktivity):
- Mounts into host Rails application (e.g., Hacktivity) via
config/routes.rb - Uses host app's
current_uservia Devise for player authentication - Game frontend served from
app/views/andpublic/assets - Scenario data and player progress persisted via Rails models (
app/models/) - Solution validation endpoints exposed as Rails controllers (
app/controllers/) - Admin/instructor UI for scenario management runs in the host application
- Server-side validation of all solutions prevents client-side tampering and ensures assessment integrity
Core Systems (Sequential Initialization)
- Game Engine (
js/core/game.js): Phaser.js initialization, scene management (preload → create → update) - Rooms (
js/core/rooms.js): Dynamic room loading from JSON scenarios, depth layering by Y-position + layer offset - Player (
js/core/player.js): Character sprite with pathfinding, keyboard/mouse controls, animation system - Systems (
js/systems/): Modular subsystems (interactions, inventory, doors, collisions, biometrics) - Mini-games (
js/minigames/): Framework-based educational challenges (lockpicking, password, biometrics, etc.)
Data Flow
- Scenarios (JSON) → loaded into
window.gameScenario→ populate rooms/objects → create interactive environment - Player Actions → interaction system checks proximity → triggers object interactions or mini-games
- Game State stored in
window.gameState:{ biometricSamples, bluetoothDevices, notes, startTime }
Global Window Object
Break Escape attaches critical runtime objects to window for cross-module access (no complex bundling):
window.game // Phaser game instance
window.gameScenario // Current scenario JSON
window.player // Player sprite
window.rooms // Object of room data
window.gameState // Persistent game state
window.inventory // Player's collected items
Key Patterns & Conventions
Room System & Depth Calculation
Every object's depth = worldY + layerOffset (not Z-index). This ensures correct perspective in top-down view:
- Walls:
roomY + 0.2 - Interactive Objects:
objectBottomY + 0.5 - Player:
playerBottomY + 0.5 - Doors:
doorY + 0.45
See js/core/rooms.js (lines 1-40) for detailed depth hierarchy documentation.
Object Interactions
- Objects must have
interactable: trueandactive: truein scenario JSON - Interaction distance:
INTERACTION_RANGE = 64px(checked every 100ms) - Interaction handlers in
js/systems/interactions.jsdispatch to specialized systems:- Locks:
unlock-system.js(key-based, password, PIN, biometric) - Doors:
doors.js(movement triggers) - Inventory:
inventory.js(item collection) - Biometrics:
biometrics.js(fingerprint collection/scanning)
- Locks:
Mini-game Framework
All mini-games extend MinigameScene (js/minigames/framework/base-minigame.js):
// Registration in js/minigames/index.js
MinigameFramework.registerScene('game-name', GameClass);
// Usage
window.MinigameFramework.startMinigame('game-name', { data });
Mini-games handle modal display, pause/resume, and return callbacks automatically.
Inventory System
- Items stored as objects with
id,name,textureproperties - Item identifiers created via
createItemIdentifier()for UI display - Starting items defined in
startItemsInInventoryarray at scenario root level - Starting items automatically added to inventory on game initialization
Scenario JSON Structure
{
"scenario_brief": "Mission description",
"endGoal": "What player must accomplish",
"startRoom": "room_id",
"startItemsInInventory": [
{
"type": "object_type",
"name": "Display name",
"takeable": true,
"observations": "Item description"
}
],
"rooms": {
"room_id": {
"type": "room_type",
"connections": { "north": "next_room" },
"objects": [
{
"type": "object_type",
"name": "Display name",
"takeable": false,
"interactable": true,
"scenarioData": { /* unlock conditions */ }
}
]
}
}
}
Essential Development Workflows
Adding a New Security Challenge
- Create mini-game class in
js/minigames/{challenge-name}/ - Extend
MinigameScenebase class (seejs/minigames/framework/base-minigame.js) - Register in
js/minigames/index.jsand export - Trigger from interactions via
window.MinigameFramework.startMinigame()
Adding Scenario Content
- Create
scenarios/{name}.jsonwith room/object definitions - Use existing room types from
assets/rooms/*.jsonTiled files - Objects must match registered texture names (loaded in
game.jspreload) - Reference scenarios from
scenario_select.html
Debugging Game Issues
- Player stuck/pathfinding: Check
STUCK_THRESHOLD(1px) andPATH_UPDATE_INTERVAL(500ms) inconstants.js - Object not interactive: Verify
interactable: true,active: true, andINTERACTION_RANGEdistance in scenario JSON - Depth/layering wrong: Recalculate depth =
worldY + layerOffsetinrooms.jshierarchy - Mini-game not loading: Verify registered in
minigames/index.jsand exported from minigame class
Project-Specific Patterns
Tiled Map Integration
Rooms use Tiled editor JSON format (assets/rooms/*.tmj). Key workflow:
- Objects stored in
map.getObjectLayer()collections - Tiled object GID → texture lookup via tileset registry
TiledItemPoolclass manages available objects to prevent duplicates
External Dependencies
- Phaser.js v3.60: Game engine (graphics, physics, input)
- EasyStar.js v0.4.4: Pathfinding (A* algorithm for player movement)
- CyberChef v10.19.4: Embedded crypto tools (iframe-based in laptop minigame)
URL Versioning Convention
Assets use query string versioning: import { x } from 'file.js?v=7' to bust browser cache during development.
CSS Styling Conventions
Maintain pixel-art aesthetic consistency:
- Avoid
border-radius- All UI elements use sharp, 90-degree corners - Borders must be exactly 2px - This matches the pixel-art tile size (32px tiles = 2px scale factor)
- Examples: buttons, panels, modals, and input fields in
css/*.css
Quick Command Reference
Local Development
python3 -m http.server # Start local web server (root dir)
# Access: http://localhost:8000/scenario_select.html
Scenario Testing
- Edit scenario JSON directly
- Reload browser (hard refresh if using version queries)
- Test from
scenario_select.htmldropdown
Files to Read First When Onboarding
README.md- Project overview and feature listjs/main.js- Game initialization and global state setupjs/core/game.js- Phaser scene lifecycle and asset loadingjs/core/rooms.js- Room management and depth layering documentationscenarios/biometric_breach.json- Full example scenario structurejs/minigames/framework/minigame-manager.js- Mini-game architecture