## What Is a Text Adventure Game and Why Build One in the Browser?
Text adventure games, often called interactive fiction, emerged in the late 1970s with titles like Zork and Colossal Cave Adventure. Players type commands such as "go north" or "take key" to navigate worlds, solve puzzles, and uncover stories. These games rely on imagination, powered by descriptive text rather than graphics.
Building one in the browser offers unique advantages: instant accessibility without downloads, easy sharing via a single HTML file, and the ability to run on any modern device. No servers or frameworks needed—just vanilla HTML, CSS, and JavaScript. This approach teaches core web technologies while creating something fun and nostalgic. Imagine sharing a self-contained game with friends; they open it and dive right in.
In this guide, we'll construct a complete example step by step. You'll end up with a game featuring multiple rooms, movable items, and a command parser. For the full source code, check out the [GitHub repository](https://github.com/thecodeabides/browser-text-adventure).
## How Do We Structure the Basic HTML Skeleton?
Start with a minimal HTML page to host the game. We need a container for the game interface, an area to display output (like room descriptions and responses), and an input field for player commands.
Consider this layout:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text Adventure Game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="game">
<div id="output"></div>
<div id="input-line">
<span id="prompt">></span>
<input id="command" type="text" autocomplete="off" autofocus>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
```
Here, `#output` holds the game's text history. `#input-line` includes a prompt (`>`) and the command input, which auto-focuses for seamless play. The `autocomplete="off"` prevents browser suggestions from interfering. This setup mimics a terminal, evoking classic adventure games.
## What Styling Makes It Feel Like a Real Adventure?
CSS transforms the plain structure into an immersive retro terminal. Use a monospaced font, dark background, and green text for that 1980s vibe. Add subtle animations for output to enhance feedback.
Key styles:
```css
body {
margin: 0;
padding: 20px;
font-family: 'Courier New', monospace;
background: #000;
color: #00ff00;
}
#game {
max-width: 800px;
margin: 0 auto;
}
#output {
min-height: 400px;
padding: 10px;
border: 1px solid #00ff00;
overflow-y: auto;
white-space: pre-wrap;
}
#input-line {
display: flex;
align-items: center;
margin-top: 10px;
}
#prompt {
margin-right: 5px;
}
#command {
flex: 1;
background: transparent;
border: none;
color: #00ff00;
font-family: inherit;
font-size: 16px;
}
#command:focus {
outline: none;
}
```
The `white-space: pre-wrap` preserves line breaks and spacing in descriptions. `overflow-y: auto` scrolls older output as the game progresses. This creates a focused, distraction-free window into your adventure world.
## How Does the JavaScript Bring the Game to Life?
JavaScript manages the game state and processes inputs. We'll define rooms, track the player's location and inventory, and build a parser for natural-language commands.
### Initializing Game State
Core data structures:
- `currentRoom`: Tracks the player's location (e.g., 'kitchen').
- `rooms`: Object mapping room names to details like description, exits, and items.
- `inventory`: Array of held items.
- `outputHistory`: Array for all displayed text, enabling scrolling history.
Example initialization:
```javascript
const game = {
currentRoom: 'kitchen',
rooms: {},
inventory: [],
outputHistory: []
};
```
Populate `rooms` with specifics:
```javascript
game.rooms = {
kitchen: {
description: 'You are in the kitchen. There is a shiny key on the table and a door to the north.',
exits: { north: 'hallway' },
items: ['key']
},
hallway: {
description: 'You are in the hallway. There is a door to the south and a treasure chest to the north, but it is locked.',
exits: { south: 'kitchen', north: 'treasure' },
items: []
},
treasure: {
description: 'You are standing in front of a treasure chest. It is open and you can see gold inside! Congratulations!!!',
exits: { south: 'hallway' },
items: []
}
};
```
Each room has a vivid description, directional exits, and potential items. This modular setup allows easy expansion—add more rooms or puzzles effortlessly.
### Handling Output and Input
Create functions to print text and capture commands:
```javascript
function print(text) {
game.outputHistory.push(text);
const output = document.getElementById('output');
output.textContent = game.outputHistory.join('\
');
output.scrollTop = output.scrollHeight;
}
function getCommand() {
const command = document.getElementById('command').value.trim().toLowerCase();
document.getElementById('command').value = '';
return command;
}
```
`print` appends to history, updates the DOM, and auto-scrolls. Input is normalized (trimmed, lowercased) for consistent parsing.
### Building the Command Parser
The parser interprets player input. It handles movement (`go north`), item actions (`take key`, `drop key`), inspection (`look`, `inventory`), and more.
```javascript
function parse(command) {
const words = command.split(' ');
const action = words[0];
const arg = words.slice(1).join(' ');
switch (action) {
case 'go':
move(arg);
break;
case 'take':
takeItem(arg);
break;
case 'drop':
dropItem(arg);
break;
case 'look':
look();
break;
case 'inventory':
inventory();
break;
default:
print('I don\\'t understand that command.');
}
}
```
This switch statement routes commands. Aliases like `north` map to `go north` for brevity—expand `move` to handle them.
### Implementing Movement
```javascript
function move(direction) {
const room = game.rooms[game.currentRoom];
if (room.exits[direction]) {
game.currentRoom = room.exits[direction];
look();
} else {
print('You can\\'t go that way.');
}
}
```
Checks exits and updates location, then refreshes the view with `look()`.
### Managing Items and Inventory
```javascript
function look() {
const room = game.rooms[game.currentRoom];
let output = room.description;
if (room.items.length > 0) {
output += ' ' + room.items.join(', ');
}
if (game.inventory.length > 0) {
output += ' You are carrying: ' + game.inventory.join(', ');
}
print(output);
}
function takeItem(item) {
const room = game.rooms[game.currentRoom];
const index = room.items.indexOf(item);
if (index !== -1) {
room.items.splice(index, 1);
game.inventory.push(item);
print('You take the ' + item + '.');
} else {
print('There\\'s no ' + item + ' here.');
}
}
function dropItem(item) {
const index = game.inventory.indexOf(item);
if (index !== -1) {
game.inventory.splice(index, 1);
game.rooms[game.currentRoom].items.push(item);
print('You drop the ' + item + '.');
} else {
print('You don\\'t have a ' + item + '.');
}
}
function inventory() {
if (game.inventory.length === 0) {
print('You are carrying nothing.');
} else {
print('You are carrying: ' + game.inventory.join(', '));
}
}
```
These functions dynamically update rooms and inventory. In our example, grabbing the key from the kitchen unlocks the treasure room narrative.
## Wiring Up Event Listeners
Tie it together:
```javascript
document.getElementById('command').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
const command = getCommand();
if (command) {
print('> ' + command);
parse(command);
}
}
});
// Start the game
print('Welcome to the Text Adventure! Type "look" to start exploring.');
look();
```
Enter triggers parsing; initial `look()` sets the scene.
## Exploring Enhancements and Real-World Applications
This foundation supports expansions: add puzzles (e.g., key unlocks door), save/load via localStorage, or multiplayer with WebSockets. For accessibility, add ARIA labels and voice input via Web Speech API.
Real-world uses? Educational tools for teaching programming logic, interactive storytelling for writers, or portfolio projects showcasing DOM manipulation and event handling.
Test in any browser—works offline as a single file. Tinker with rooms to create your narrative. The [GitHub repo](https://github.com/thecodeabides/browser-text-adventure) has the polished version; fork it to iterate.
By following these steps, you've built a functional text adventure. Experiment, and watch your game world grow!
---
<div style="text-align: center; margin-top: 2rem;">
<a href="https://thecodeabides.com/blog/build-a-browser-text-adventure-game/" target="_blank" rel="noopener noreferrer" class="view-full-resource-btn" style="display: inline-block; background-color: #f97316; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600; transition: background-color 0.2s;">View Full Resource</a>
</div>