charity: water logo
๐Ÿ•น Game Blueprint

Water Path โ€” Game Logic

Blueprint for the Water Path game, as implemented in index.html. All core gameplay logic and UI flows are described for design and development.

๐Ÿ›  HTML ยท CSS ยท JS
๐Ÿ“ฑ Desktop (responsive)
๐ŸŽฏ Audience: All ages, puzzle fans
1
Game Start
- What happens when the game first loads or starts?
๐Ÿ FeatureMain Menu & State
UI Element
A full-screen main menu appears with charity: water branding: a navyโ†’teal hero banner with the logo, mission tagline ("696 million people lack basic access to clean water"), and a "Visit charitywater.org" CTA button. Below are How to Play and Important Rules boxes, a Start Game button, and a Resume Game button (shown only if saved progress exists). Animated clouds and a sun render in the background โ€” no timer.
What to Code
On DOMContentLoaded, call showMainMenu(). If a saved state exists in localStorage, show Resume Game option. On Start: clearGameState() wipes localStorage, resetGame() initializes level 1 fresh. On Resume: loadGameState() restores grid, lives, level, points from localStorage and the grid renders at the saved level.
Tech Needed
DOMContentLoadedlocalStorageshowMainMenu()resetGame()
- Are any elements placed on the screen? (e.g., items, score, timer)
๐Ÿ—บFeatureGame Elements
UI Element
An 8ร—8 grid renders centered above the dashboard. The well (๐Ÿ’ง) is always at top-left [0,0], the village (๐Ÿ ) at bottom-right [7,7]. Obstacles use country-specific emoji (๐Ÿฆ๐Ÿ˜๐ŸŒพ for Ethiopia, etc.) and are deterministic per level. Below the grid, the dashboard has: a logo+tagline row, a stats row with lives (๐Ÿ’ง๐Ÿ’ง๐Ÿ’ง) and water used (๐Ÿ’ง 0/15), a row with level/points/highscore cards, and action buttons (Submit Path, Reset Path, Main Menu, LOGIC). All charity: water elements use teal (#1AADD5) and navy (#003366) brand colors. No timer.
What to Code
On game start, generateGrid() places well, village, and obstacles. Levels 1-10 use fixed levelLayouts[] arrays. Levels 11+ randomize obstacles validated by BFS to ensure solvability. renderGrid() builds DOM cells with role="grid", role="row", role="gridcell", aria-label, and tabindex for accessibility. updateUI() syncs all dashboard stat elements.
Tech Needed
generateGrid()renderGrid()updateUI()levelLayouts[]hasPath() BFSrole=grid
2
Player Actions
- What can the player click, tap, move, or do?
๐Ÿ–ฑFeaturePlayer Actions
UI Element
Player clicks grid cells to build a path from the well to the village. First click must be the well cell [0,0]. Subsequent clicks must be orthogonally adjacent to the last selected cell. Clicking an already-selected cell deselects it and all cells after it. Obstacles cannot be selected. Buttons: Submit Path, Reset Path (costs 1 life), Main Menu. Keyboard: Arrow keys navigate cells, Enter or Space selects/deselects the focused cell. All cells have tabindex for keyboard access.
What to Code
Click events on cells via handleCellClick(). handleGridKeydown() manages arrow-key navigation. Track selected path as an array of {r, c} objects. Prevent selection of obstacles, non-adjacent cells, or wrong start cell. Each dashboard stat has aria-live="polite" for real-time screen reader updates.
Tech Needed
handleCellClick()handleGridKeydown()aria-livetabindexselectedPath[]
- How does the game respond to those actions?
๐Ÿ”ตFeatureGame Response
UI Element
Selected cells highlight in teal (#1AADD5) with a dashed border for color-blind accessibility. Invalid actions (obstacle, non-adjacent, wrong start) flash the cell red briefly via .cell-error CSS class. The dashboard stats (lives, water count, level, points) update live. Submitting validates the path and shows a success popup or error popup. The grid uses role="grid", role="row", and role="gridcell" for screen readers.
What to Code
Toggle .selected and .cell-error CSS classes. Call updateUI() after any state change. showPopup() renders feedback modals. renderGrid() updates aria-selected and aria-label on each cell to reflect its state. All interactive elements have :focus-visible teal outline for keyboard users.
Tech Needed
.selected / .cell-errorupdateUI()showPopup()aria-selected:focus-visible
3
Game Logic
- What rules or conditions should the game check for?
๐Ÿ”—FeatureGame Rules
UI Element
On submit, the game validates: path starts at well [0,0], path ends at village [7,7], all steps are orthogonally adjacent (no diagonals), no cell is repeated, no obstacle cells are in the path, and path length โ‰ค maxWater (starts at 15, decreases ~1 per level as difficulty rises).
What to Code
Validate path array in submitPath(): first cell is well, last is village, all steps adjacent (dr+dc===1), no repeats via selectedPath.some(), no obstacles via grid[r][c].type, and length โ‰ค maxWater. Show specific error popup if any rule fails. Obstacle validation is redundant since obstacles can't be clicked, but kept as a safeguard.
Tech Needed
submitPath()hasPath() BFSarray validationshowPopup()
- What happens when the player succeeds or fails at something?
โœ…FeatureSuccess/Failure
UI Element
On success: teal success popup shows country flag, water used (e.g. "๐Ÿ’ง 7 / 15"), points breakdown (+100 base, +waterBonus, +levelBonus), and the country-specific fact. Next Level button appears inside the popup. On failure (bad path): error popup with specific message ("Path must reach the village!", "Not enough water! Used X/Y drops."). If lives reach 0: full Game Over modal with final score, level reached, and a Try Again button.
What to Code
On success: calculate points = 100 + (maxWater-waterUsed)*10 + level*50 - pathObstacles*5. Call showPopup(msg, 'green') with country flag and fact. Set submittedThisAttempt=true, gameActive=false. On failure: showPopup(msg, color) with 'red' or 'orange'. On lives=0: gameOver() shows Game Over modal. On Next Level: nextLevel() increments level, lowers maxWater, raises obstacle count, regenerates grid.
Tech Needed
submitPath()showPopup()nextLevel()gameOver()submittedThisAttempt
4
Score / Feedback
- How is the score updated?
๐ŸงฎFeatureScore Update
UI Element
Points per level = 100 + (maxWater - waterUsed)*10 + level*50 - obstacleCount*5. Base 100 pts, water bonus (shorter path = more), level bonus (higher level = more), obstacle penalty. Total points accumulates across all levels. High score persists in localStorage. Dashboard shows live: current level, current points, best score. All stat elements have aria-live="polite" so screen readers announce changes immediately.
What to Code
In submitPath(): waterBonus = Math.max(0, (maxWater - waterUsed) * 10), levelBonus = level * 50, points = 100 + waterBonus + levelBonus - obstacleBonus. Add to totalPoints. If totalPoints > highscore update highscore. Call saveHighscore() and saveGameState(). All dashboard stat divs have aria-live="polite" aria-atomic="true" attributes.
Tech Needed
submitPath()saveHighscore()saveGameState()aria-livelocalStorage
- What visual or audio feedback appears based on player actions?
๐ŸŒŠFeatureFeedback
UI Element
Selected cells highlight teal (#1AADD5) with a dashed border (color-blind accessible). Invalid actions flash red for 400ms via CSS animation. Success popup: green-themed modal with charity: water logo, country flag, water used, points breakdown, country fact, and "Donate at charitywater.org" button. Error popup: red/orange tinted with specific message. Game Over modal: navy-themed with final score, level reached, country fact, and donate CTA. No audio in this implementation.
What to Code
.selected class applies teal background + dashed border. .cell-error applies red background for 400ms then removes. showPopup(msg, color) renders modals: 'green' for success, 'red'/'orange' for errors. Popup HTML includes charity: water logo, flag emoji, fact text, and a donate link. Game Over uses role="dialog" aria-modal="true" for accessibility. All animations respect prefers-reduced-motion.
Tech Needed
.selected / .cell-errorshowPopup()role=dialogprefers-reduced-motionaria-modal
5
Win or Lose Conditions
- How does the game end?
๐ŸŽ‰FeatureGame End
UI Element
The game has no traditional win state โ€” it progresses infinitely. Levels 1โ€“10 use 10 country themes with deterministic obstacle layouts. Level 11+ use randomized solvable layouts with increasing difficulty. The game ends only when all 3 lives are lost, triggering the Game Over modal with final score, level reached, a country fact, and a donate CTA.
What to Code
Track lives in state. When lives === 0 after a Reset, call gameOver(). This shows the Game Over modal and calls clearGameState(). Levels beyond 10 fall back to generateGrid() random obstacle placement validated by BFS to remain solvable.
Tech Needed
gameOver()clearGameState()hasPath() BFSlives state
- What happens when the game ends (e.g., show a message, reset option)?
๐Ÿ“คFeatureEnd Actions
UI Element
Game Over modal shows: "Game Over" title, final score, level reached, a country fact about global water access, a "Donate at charitywater.org โ†’" button, and a "Try Again" button. The Main Menu button is always accessible during gameplay โ€” it saves progress before returning.
What to Code
On Try Again: clearGameState(), level = 1, totalPoints = 0, lives = 3, showMainMenu(). On Main Menu: saveGameState() then showMainMenu(). Game Over modal uses role="dialog" aria-modal="true" for accessibility.
Tech Needed
clearGameState()showMainMenu()saveGameState()role=dialogrenderGrid()updateUI()
6
Reset / Replay
- Can the player restart the game? What happens on reset?
๐Ÿ”FeatureReset/Replay
UI Element
Three reset paths exist: Reset Path clears the drawn path and costs 1 life. Try Again in the Game Over modal resets level/points/lives and returns to main menu. Main Menu saves progress first. DEV TOOLS cheat buttons exist for testing only. Three reset paths exist: Reset Path button clears the drawn path and costs 1 life. Try Again in the Game Over modal resets level/points/lives and returns to main menu. Main Menu saves progress first. A DEV TOOLS row with cheat buttons (+1 Level, -1 Life, +1 Life, Clear Save) exists for testing only.
What to Code
Reset Path: selectedPath=[], lives--, renderGrid(), updateUI(), saveGameState(). Try Again: clearGameState(), level=1, totalPoints=0, lives=3, showMainMenu(). Main Menu: saveGameState() then showMainMenu(). Cheat buttons mutate state directly.
Tech Needed
resetPath()clearGameState()saveGameState()showMainMenu()renderGrid()updateUI()