Version: 0.1.0
Genre: 8-bit Style Resource Management Survival Game
Platform: Web Browser (HTML5 Canvas)
Pilgrim Trail is a retro-styled survival game in the spirit of Oregon Trail, where you guide a party of pilgrims across 79 miles of treacherous wilderness on their journey to Plymouth. Manage your resources carefully, hunt for food, and decide when to travel or rest to ensure your party survives the journey.
- Open
index.htmlin a modern web browser - Press SPACE to start traveling
- Press H when stopped to hunt for food
- Reach Mile 79 to complete the pilgrimage!
Pilgrim-Trail-Game/
├── index.html # Entry point - minimal HTML structure and styling
├── game.js # Core game logic and state management
├── renderer.js # Canvas rendering system (8-bit aesthetic)
└── README.md # This documentation file
| File | Purpose |
|---|---|
index.html |
HTML structure, CSS styling, script loading order |
game.js |
Game state, update logic, save/load, input handling, game loop |
renderer.js |
Canvas initialization, drawing functions, UI rendering |
- Time advances automatically (1 day = 5 seconds real-time)
- Each day consumes 2 food per survivor
- Game ends if food reaches 0 (starvation)
- Destination: 79 miles
- Travel Speed: 3 miles per day (when traveling)
- Victory Condition: Reach Mile 79 with at least 1 survivor alive
- Toggle with SPACE key
- Traveling: Advances 3 miles per day, cannot hunt
- Stopped: No distance progress, can hunt for food
- Press H to hunt (only when stopped)
- Success Rate: 70%
- Food Gained: 5-15 (uniform random) on success
- Cost: Uses 1 full day (food consumed, day advances)
- Result displayed for 2 seconds
Random events occur while traveling, referencing actual Mayflower passengers for historical immersion.
- Condition: Only while traveling
- Timing: Checked every 2 days
- Probability: 20% chance per check
- Display: Current event shown for 3 seconds
| # | Event | Effect |
|---|---|---|
| 1 | "Priscilla Mullins found wild berries" | +8 Food |
| 2 | "William Bradford fell ill" | -1 mile/day for 3 days |
| 3 | "Fair winds aided progress" | +2 miles today |
| 4 | "Edward Winslow negotiated safe passage" | +5 miles today |
| 5 | "John Howland swept overboard but saved!" | No effect (tension) |
| 6 | "Myles Standish spotted potential threat" | Forced stop for 1 day |
| 7 | "Elizabeth Hopkins gave birth to Oceanus" | +1 survivor, -2 days |
| 8 | "Storm damaged supplies" | -5 Food |
- Displays last 3 events
- Most recent event shown prominently
- Older events fade in the log
- Speed Penalty: Shows remaining days and reduction
- Forced Stop: "Halted!" status in red
| Resource | Starting Amount | Consumption |
|---|---|---|
| Food | 100 | 2 per survivor per day |
| Survivors | 4 | - |
| Condition | Outcome |
|---|---|
| Reach Mile 79 | Victory! |
| Food reaches 0 | Game Over (Starvation) |
| All survivors die | Game Over |
| Key | Action | Condition |
|---|---|---|
| SPACE | Toggle Travel/Stop | Not in game over |
| H | Hunt for food | Stopped only |
| Q | Quit game | Not in game over |
| Key | Action | Condition |
|---|---|---|
| S | Save game | Always |
| L | Load game | Always |
| R | Restart game | Game over only |
The game uses a pure functional state management approach:
// State is never mutated directly
const newState = updateFunction(oldState, parameters);Key Principles:
- All state updates return new state objects
- Deep cloning via
JSON.parse(JSON.stringify())prevents mutation - Single source of truth in
GameLoop.state
{
day: 1, // Current day counter
dayProgress: 0, // 0-1 progress toward next day
resources: {
food: 100,
water: 100,
medicine: 20
},
party: {
survivors: 4,
morale: 100,
health: 100
},
settings: {
dayDuration: 5000, // ms per day
foodPerSurvivor: 2, // consumption rate
milesPerDay: 3, // travel speed
destinationMiles: 79 // goal distance
},
miles: 0, // current distance traveled
traveling: false, // travel mode toggle
huntResult: null, // last hunt outcome
huntResultTimer: 0, // display timer for hunt result
// Event System
eventLog: [], // Array of last 3 events
eventCounter: 0, // Days since last event check
currentEvent: null, // Active event with timer
modifiers: {
speedPenalty: 0, // Miles/day reduction
speedPenaltyDays: 0, // Days remaining
forcedStop: false, // Must stop traveling
forcedStopDays: 0 // Days remaining
},
gameOver: false,
gameOverReason: '',
victory: false,
exited: false
}Uses a fixed timestep architecture for deterministic updates:
┌─────────────────────────────────────────────────┐
│ requestAnimationFrame │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Calculate Delta Time │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Fixed Logic Updates (10Hz / 100ms) │ │
│ │ - Day progression │ │
│ │ - Resource consumption │ │
│ │ - Distance tracking │ │
│ │ - Victory/defeat checks │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Render (Display refresh rate) │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Benefits:
- Consistent gameplay regardless of frame rate
- Prevents physics/timing glitches
- Separates logic from rendering
The renderer is completely decoupled from game logic:
// Game logic knows nothing about rendering
Renderer.render(state, notification);8-bit Color Palette:
- 16 colors inspired by CGA/EGA era
- Consistent theming throughout UI
- Color-coded status indicators
- Update State (
game.jsline ~14):
resources: {
food: 100,
water: 100,
medicine: 20,
newResource: 50 // Add here
}- Add Consumption Logic (
applyDailyConsumption):
state.resources.newResource -= consumptionRate;- Update Renderer (
renderStatusinrenderer.js):
this.drawTextShadow(`Resource: ${state.resources.newResource}`, x, y, color);- Create Action Function (
game.js):
function newAction(state) {
if (state.gameOver || state.exited) return state;
const newState = JSON.parse(JSON.stringify(state));
// Modify newState
return newState;
}- Add Key Binding (
setupInputingame.js):
} else if (key === 'X' && !this.state.gameOver) {
this.state = newAction(this.state);
this.showNotification('Action performed!');
}- Update Controls Display (
renderControlsinrenderer.js)
- Create Event Check Function (
game.js):
function checkForEvent(state) {
if (Math.random() < 0.1) { // 10% chance per day
// Apply event effects
}
return state;
}- Call from Day Progression (
updateTimefunction):
while (newState.dayProgress >= 1) {
// ... existing code ...
newState = checkForEvent(newState);
}- Add to Renderer Object (
renderer.js):
renderNewEffect(state) {
// Use existing drawing methods:
// this.drawRect(), this.drawText(), this.drawTextShadow()
}- Call from Main Render:
render(state, notification) {
// ... existing code ...
this.renderNewEffect(state);
}- Storage: Browser localStorage
- Key:
pilgrim_trail_save - Format: JSON-serialized game state
saveGame(state) // Returns { success: bool, message: string }
loadGame() // Returns { success: bool, state: object, message: string }
deleteSave() // Removes save data
hasSaveData() // Returns boolean| Spec | Value |
|---|---|
| Canvas Resolution | 640 × 480 (logical) |
| Rendering | HTML5 Canvas 2D |
| Logic Update Rate | 10 Hz (100ms fixed step) |
| Render Rate | Display refresh rate |
| Font | Monospace system font |
| Image Smoothing | Disabled (crisp pixels) |
- Chrome 60+
- Firefox 55+
- Safari 11+
- Edge 79+
Proprietary - GillSystems
Built following the 7D Agile SDLC methodology:
- DEFINE → Requirements captured
- DESIGN → Architecture planned
- DEVELOP → Iterative implementation
- DEBUG → Testing and validation
- DOCUMENT → This README
- DELIVER → Packaged for distribution
- DEPLOY → Ready for deployment