Choose Your Own Adventure — Web Application Project Report
CYOA Maker is a web application that lets users create and play Choose Your Own Adventure stories — interactive, branching narratives where the reader makes choices that determine how the story unfolds. Think of it as a lightweight, browser-based tool for writing the kind of adventure books that were popular in the 1980s and 1990s, but published on the web and playable by anyone with a browser.
A story is made up of story points — individual scenes or moments in the narrative. Each story point can have one or more choices that link to other story points, creating a web of possible paths through the story. Authors control the flow, and players experience a different adventure depending on the decisions they make.

This project was built as a Grade 12 Web Technologies assignment. The goal was to design and build a complete, functional, multi-user web application from scratch — covering everything from database design and server-side PHP logic to front-end styling and user experience.
Key goals included:
The homepage (index.php) displays a gallery of all published stories as cards.
Each card shows the story's title, a short description, the author's name, creation date, and
a thumbnail image. No login is required to browse or play — the app is open to anyone.
Clicking a story launches the player (play.php). The player renders the current
story point — its title, description text, and optional image — along with clickable choice
buttons that advance the story. Players navigate the branching path until they reach an
ending (a story point with no choices).

Logged-in users also see a "My Stories" filter on the homepage to quickly find their own work, and a "Clone" button that lets them copy any story into their own account as a starting point for a new one.
Registered users can create new stories through the editor (editor.php). The
editor has three distinct views, all handled within a single file:


Choices are added dynamically on the story point form. Each choice has a label (the button text the player sees) and a destination (which story point it leads to). Authors can add, reorder, and remove choices before saving.
Any logged-in user can clone any story on the homepage. Cloning creates a full, independent copy under the user's account — including all story points and choices — with a new title. All internal choice links are automatically remapped to the new copy's story points, so the cloned story works correctly from the start.
Each story has a theme that controls the visual style of the play page. There are five themes to choose from:
In addition to the theme, authors can choose one of three image layouts for
how story point images are positioned on the play page:
image_left, image_right, or image_top.


Users register with their name, email address, and a password. After logging in, they can
visit their account page (account.php) to update their profile picture.
Passwords are never stored in plain text — they are hashed using the industry-standard
bcrypt algorithm before being saved.

Users flagged as administrators see an extra panel on the account page. The admin panel provides the following capabilities:
The main admin account is defined in config.php using the
MAIN_ADMIN constant, which prevents that account from being accidentally
demoted or deleted.

The app uses PHPMailer with Gmail SMTP to send two types of emails:
template/welcome.html) (sample below).
| Layer | Technology | Notes |
|---|---|---|
| Backend language | PHP (procedural) | No framework — plain PHP files |
| Database | MySQL (mysqli) | Hosted database server; queries use prepared statements |
| PHPMailer + Gmail SMTP | For welcome emails and password resets | |
| Front-end | Vanilla JavaScript | No frameworks (no React, jQuery, etc.) |
| Fonts | Inter + Crimson Text | Loaded via Google Fonts |
| DB Admin Tool | phpMyAdmin | Browser-based MySQL admin tool |
The project is organized as a single web root folder. Here are the key files and folders:
cyoa_maker/
├── config.php # DB path, SMTP config, MAIN_ADMIN constant
├── db_functions.php # All database CRUD functions
├── index.php # Homepage — story gallery
├── editor.php # Story editor (3 views in one file)
├── play.php # Story player — loads theme CSS dynamically
├── account.php # User profile + admin panel
├── header.php # Shared navigation bar (included on every page)
├── login.php # Login form
├── register.php # Registration form
├── forgot_password.php # Send password reset email
├── reset_password.php # Accept reset token, set new password
├── logout.php # Destroy session + redirect
├── mail_helper.php # PHPMailer wrapper function
│
├── styles/ # CSS files (split by page/component)
│ ├── styles.css # Base styles, navbar, buttons, layout
│ ├── cards.css # Story gallery cards
│ ├── forms.css # Auth and editor forms
│ ├── editor.css # Editor-specific layout
│ └── account.css # Account and admin panel styles
│
├── report/ # folder of this report
│ ├── index.php # this report
│ └── 01.png # screen shots for report
│
├── themes/ # Per-story play-page themes
│ ├── egyptian_theme.css
│ ├── forest_theme.css
│ ├── scifi_theme.css
│ ├── ocean_theme.css
│ └── desert_theme.css
│
├── images/
│ ├── {storyID}/ # Cover and story point images (one folder per story)
│ └── profiles/ # User profile images
│
├── phpmailer/ # PHPMailer library files
│
└── template/
└── welcome.html # Welcome email HTML template
The styles/ folder contains five CSS files, each focused on a different part
of the app. styles.css provides the foundation — global typography, the
navigation bar, buttons, and the overall page layout. The other files add styles specific
to their component: gallery cards, forms, the editor layout, and the account panel.
This split keeps each file manageable and avoids one giant stylesheet.
The play page (play.php) is styled entirely differently from the rest of the
app — each story has its own theme. When a player opens a story, play.php
reads the story's saved theme name (e.g., forest) and dynamically builds a
<link> tag pointing to themes/forest_theme.css.
All five theme files define the same set of CSS classes (e.g., .container,
.choices, .banner), so the play page HTML never changes — only
the stylesheet swaps out. Image layout variants (image_left,
image_right, image_top) are applied as a class on the
<body> tag and handled within each theme file.
The project uses MySQL as its database, accessed via PHP's
mysqli extension. MySQL is the standard database for shared PHP hosting
environments and was taught in class, making it the natural choice. All queries use
prepared statements with bound parameters to prevent SQL injection.
phpMyAdmin is a browser-based admin tool for MySQL databases. It is typically pre-installed on shared hosting control panels (cPanel) and in local stacks like XAMPP. It allows developers to inspect tables, run SQL queries, and view or edit records without needing a separate desktop tool.
All tables use the prefix cyoam1_. There are five tables:
| Table | Purpose |
|---|---|
cyoam1_users | Stores registered user accounts (name, email, hashed password, admin flag, profile image) |
cyoam1_stories | Stores stories (title, description, cover image, theme, layout, author) |
cyoam1_storypoints | Stores individual scenes within a story (title, narrative text, image, hint) |
cyoam1_choices | Stores the branching choices for each story point (button label + destination story point) |
cyoam1_password_resets | Stores temporary password-reset tokens with a 1-hour expiry |
The data has a clear hierarchy:
Users (1) ──── (N) Stories (1) ──── (N) StoryPoints (1) ──── (N) Choices
│
destinationID ─────┘
(links to another StoryPoint)
The first story point added to a story (lowest storypointID) is automatically
treated as the starting point when a player begins the story.
Each page is a self-contained PHP file. Pages that handle form submissions do so at the
very top of the file using a switch statement on a hidden action
field in the form. After processing, the page immediately redirects with
header('Location: ...') — this is called the
Post/Redirect/Get pattern and prevents duplicate form submissions on
browser refresh.
After a redirect, the page needs a way to show the user a success or error message.
This is done using PHP sessions: before redirecting, the action stores a message in
$_SESSION['flash_message'] or $_SESSION['flash_error'].
The destination page reads the message, displays it, and immediately removes it from
the session so it only appears once.
All database access goes through a single function, db_connect(), which
uses a static local variable to ensure only one mysqli connection is ever
created per request. Tables must be created on the server in advance using the provided
SQL schema file.
Security was considered throughout the project. Key measures include:
password_hash() with the bcrypt algorithm. Plain-text passwords
are never written to the database.mysqli
prepared statements with bound parameters, preventing SQL injection attacks.htmlspecialchars() to
prevent cross-site scripting (XSS). The play page is a deliberate exception —
story authors are trusted to include basic HTML formatting in their narrative text.jpg, jpeg, png, gif, webp) and saved with
randomized filenames to prevent guessable paths.CYOA Maker requires a standard PHP web server environment:
images/ directory for uploaded photosFor local development, XAMPP or Laragon work well out of the box — both include MySQL and phpMyAdmin pre-installed.
htdocs/cyoa_maker/ for XAMPP).config.php and update the settings (see Section 4.3 below).chmod 755 on Linux/macOS, or check folder permissions on Windows).http://localhost/cyoa_maker/).isAdmin = 1 for that
user in phpMyAdmin, or set the email in MAIN_ADMIN in
config.php before registering.All key settings live in config.php:
| Setting | What It Does |
|---|---|
DB_HOST, DB_USER, DB_PASSWORD, DB_NAME | MySQL connection credentials for the database server |
MAIN_ADMIN | Email address of the protected super-admin account (cannot be demoted or deleted) |
| SMTP settings | Gmail address and app password used for sending emails via PHPMailer |
This project made heavy use of AI coding tools throughout every phase of development, from the initial project proposal through implementation and all the way to writing this report. Development began with GitHub Copilot, which was used for the early stages of the project. After the monthly Copilot credits ran out, the project switched to Claude Code, which was used for the remainder of development and documentation.
In the proposal phase, AI was used to brainstorm project ideas, refine the concept, and help structure the formal project proposal document.
During implementation, AI served as a coding assistant — generating initial code for features, explaining patterns, helping debug problems, and suggesting improvements. Rather than writing every line manually, the workflow became more about describing what was needed, reviewing the generated code, testing it, and adjusting. This significantly accelerated development while still requiring a solid understanding of the underlying technology to evaluate the output correctly.
For documentation and reporting (including this report), AI helped structure content, fill in technical details, and ensure completeness. The final output still required review and editing — AI-generated writing needs human judgment to be accurate and appropriately scoped.
Overall, AI tools felt like having a knowledgeable collaborator available at all times. The key skill was learning how to communicate clearly with the AI — giving it enough context, pushing back when the output was wrong, and knowing when to accept a suggestion versus rewriting it. A selection of the prompts used throughout this project is included in Appendix A.
Moving the project from a local XAMPP setup to a real shared hosting server was straightforward. The server runs Apache with PHP and MySQL, which matches the local development environment, so no code changes were needed.
The main step was migrating the data: the local database was exported using phpMyAdmin,
and the resulting SQL file was imported into the server's database through the hosting
control panel's phpMyAdmin interface. The config.php file was then updated
with the server's database credentials and the live URL, and the app was ready.
db_functions.php made the codebase much easier to maintain and reason
about than if queries had been scattered throughout every page file.The current version of CYOA Maker covers the core create-and-play experience, but there are several features that would make the platform significantly richer:
Adding a comment section to the story play page would let players leave feedback for
authors. This would require a new cyoam1_comments table linked to stories
and users, a comment form on play.php, and a moderation option in the
admin panel.
A star rating system would help players discover the best stories in the gallery. Each registered user could rate a story once, and the average rating would be displayed on the gallery card. This would add a social element that encourages authors to put care into their stories.
Given how central AI was to the development process, integrating AI features directly into the app itself is a natural next step. Possible AI-powered features include:
This project was completed as part of the Grade 12A Web Technologies 10 course, 2025–2026.
One challenge with AI-assisted development is that it is hard to track entire conversations in the VS Code chat window — sessions get long, context gets lost, and there is no easy export. To work around this, many of the bigger feature requests were pre-written as plain text prompts before being pasted into the chat. A selection of those prompts is shown below.
I want to note that the initial project proposal was also used as a giant prompt and steering document for the AI — it was provided at the start of the project so the AI had full context about the app's goals, features, and requirements before any code was written. The prompts below are individual feature requests that were added on top of that.
This prompt was used to build the entire account.php page from scratch.
Ensuring that deleting a user or story also cleans up all related images and database records.
Adding the ability to duplicate one's own stories.
The clone operation caused the page to freeze while files were being copied.
Adding a layout selector to the story properties so authors can control how images appear during playback.
Adding the ability to disable the automatic Go Back button on individual story points.
The prompt used to start building this report.