A lightweight, real-time quiz application for classrooms and events. Host interactive quizzes with live results, scoring, and pass/fail feedback - no accounts required for participants.
- Real-time Synchronization - Questions, timers, and results sync instantly via WebSockets.
- Markdown-based Quizzes - Write and upload questions in a simple, portable Markdown format.
- Comprehensive Scoring & Leaderboards - Captures both correctness and speed. Automatically ranks winners, utilizing response times as tie-breakers.
- Post-Quiz Analytics & Dashboard - Dive deep into session data, review question difficulty (automatically identifying the hardest questions), and analyze participant performance.
- Live Response Charts - Players and presenters see beautiful chart distributions of answers after each question.
- Presenter Mode - A dedicated, full-screen view optimized for classroom projectors or remote screen sharing.
- Premium, Mobile-Optimized UI - Gradient backgrounds, circular timers, smooth animations, and a smart mobile interface for participants.
- Multi-session Support - Host multiple concurrent quiz sessions seamlessly with unique Kahoot-style 6-character codes.
- Rich Markdown & Code Highlighting - Format questions and answers with bold, italics, lists, and syntax-highlighted code blocks (
highlight.js). - Inline Quiz Previews - Test and preview your markdown formatting directly in the Admin Dashboard with a built-in mobile simulator.
- Course Metadata & Grouping - Assign course tags to sessions to easily organize and filter your Analytics dashboard.
- Test/Dry Runs - Flag sessions as test runs to exclude them from your primary analytics, or permanently delete unwanted sessions.
- Exportable Data - Export full session results and analytics to CSV for external grading or record-keeping.
- PostgreSQL Persistence - Session histories, answers, and analytics survive server restarts.
- Frictionless Onboarding - Zero setup for participants; students just enter their name and jump right in.
- Self-hosted & Free-Tier Friendly - Easily deployable to services like Render and Supabase for free.
If needed to have a presenter view, there is one that you can share in class or remote setting
Each player will have their own view
A final score will be presented for each user
Loading Questions using a Markdown Template
View progress, control flow (start, end early ..etc), and finally when done you can view summary
- Backend: Node.js, Express, Socket.IO
- Database: PostgreSQL (Supabase)
- Frontend: Vanilla HTML/CSS/JavaScript
- Charts: Chart.js
- Deployment: Render.com + Supabase (free tiers compatible)
- Node.js 18+
- PostgreSQL database (we recommend Supabase free tier)
git clone https://github.com/yourusername/markdown-mash.git
cd markdown-mash
npm installCreate a .env file:
DATABASE_URL=postgresql://user:password@host:port/your_db_name
ADMIN_PASSWORD=your_secure_passwordAdmin Password Setup: The ADMIN_PASSWORD in your .env file acts as a one-time bootstrap password. During your first login to the Admin Dashboard, the system will use this variable to permanently create your Master Admin account in the PostgreSQL database. Note: Changing the .env variable after your first login will not change your password.
Get your DATABASE_URL from Supabase:
- Create a free account at supabase.com
- Create a new project
- Go to Project Settings β Database
- Copy the "Connection pooling" URI (uses port 6543, recommended for serverless)
- Replace
[YOUR-PASSWORD]with your actual database password
π‘ Alternative PostgreSQL Providers:
- Neon: neon.tech - Serverless Postgres with generous free tier
- Railway: railway.app - Simple deployment with built-in Postgres
- ElephantSQL: elephantsql.com - Managed PostgreSQL
- Self-hosted: Any PostgreSQL 12+ instance
npm startOpen http://localhost:3000 in your browser.
- Admin Dashboard:
http://localhost:3000/admin.html - Participant Join:
http://localhost:3000/play.html - Presenter View:
http://localhost:3000/present.html
Default admin password: admin123 (change via .env)
Create quizzes in Markdown format:
# Intro to Python
# Score 100
## Q1: What does the following code print?
```python
def greet(name):
print(f"Hello, {name}!")
greet("Alice")- Hello, name!
- Hello, Alice!
- Error ::time=30
- Tuple
- List
- String
- Integer ::time=15
"The Earth is a sphere." - Science
- True
- False ::time=10
### Format Rules
| Element | Syntax | Description |
|---------|--------|-------------|
| Quiz title | `# Title` | Single `#` at the start |
| Total score | `# Score 100` | Points distributed across questions (default: 100) |
| Question | `## Q1: Text` | The `Q1:` prefix is optional. Any unmatched lines below this will be appended as multi-line text (e.g., code blocks) |
| Wrong answer | `- [ ] Option` | Unchecked checkbox |
| Correct answer | `- [x] Option` | Checked checkbox |
| Time limit | `::time=20` | Seconds per question (default: 20) |
### Scoring
- Set total points with `# Score X` (e.g., `# Score 1000`)
- Points are divided equally among questions
- Participants see their score after each question
- At the end: **Pass** (70%+) or motivating message to study more
## Hosting a Quiz
1. **Load the quiz**
- Go to Admin Dashboard
- Paste your Markdown quiz
- Click "Load Quiz"
2. **Share the link**
- Give participants the `/play.html` URL
- They enter their name to join
3. **Screen sharing (optional)**
- Open `/present.html` in a new window
- Share this window with participants for a beautiful full-screen display
- Participants can still use their own devices to answer
4. **Run the quiz**
- Click "Start Quiz"
- Click "Next Question" to advance
- Use "End Question Early" if everyone answered
- Participants and presenter view show results after each question
5. **Final results**
- Click "Show Final Results" after the last question
- Displays ranked leaderboard in admin view
- Participants see their individual scores and pass/fail status
## Deployment
### Database Setup (Required)
This app requires a PostgreSQL database. Choose one of these options:
#### Option 1: Supabase (Recommended - Free Tier)
1. Create account at [supabase.com](https://supabase.com)
2. Create new project (choose region closest to your users)
3. Go to **Project Settings** β **Database** β **Connection pooling**
4. Copy the connection string (port 6543)
5. Note your database password
**Free tier includes:** 500MB database, 2GB bandwidth, unlimited API requests
#### Option 2: Neon (Serverless Postgres)
1. Create account at [neon.tech](https://neon.tech)
2. Create new project
3. Copy the connection string from dashboard
**Free tier includes:** 512MB storage, auto-suspend after inactivity
#### Option 3: Railway (Integrated Platform)
1. Create account at [railway.app](https://railway.app)
2. Create new Postgres database
3. Copy the connection URL
**Free tier includes:** $5/month credit
#### Option 4: Self-Hosted PostgreSQL
Any PostgreSQL 12+ instance will work. You'll need:
- Host, port, database name
- Username and password
- Format: `postgresql://username:password@host:port/database`
---
### Deploy to Render.com
**Prerequisites:**
- GitHub account with this repository forked/cloned
- PostgreSQL database from one of the options above
**Steps:**
1. **Push your code to GitHub** (if you haven't already)
2. **Go to Render Dashboard**
- Visit [dashboard.render.com](https://dashboard.render.com)
- Click **New** β **Web Service**
3. **Connect Repository**
- Connect your GitHub account
- Select your MarkdownMash repository
4. **Configure Service**
- **Name**: `markdownmash` (or your choice)
- **Region**: Choose closest to your users
- **Branch**: `main`
- **Build Command**: `npm install`
- **Start Command**: `npm start`
- **Plan**: Free (or upgrade for better performance)
5. **Add Environment Variables**
Click **Advanced** β **Add Environment Variable**:
**Variable 1: DATABASE_URL**
- Key: `DATABASE_URL`
- Value: Your PostgreSQL connection string from database setup
> β οΈ **CRITICAL - Password Encoding**:
> If your database password contains special characters (`!`, `@`, `#`, `$`, `%`, `&`, etc.), you MUST URL-encode them:
> - `!` β `%21`
> - `@` β `%40`
> - `#` β `%23`
> - `$` β `%24`
> - `%` β `%25`
> - `&` β `%26`
>
> **Example:** Password `MyPass!@#` becomes `MyPass%21%40%23`
>
> **Tool:** Use [urlencoder.org](https://www.urlencoder.org/) to encode your password
**Variable 2: ADMIN_PASSWORD** (Optional)
- Key: `ADMIN_PASSWORD`
- Value: Your custom admin password (default is `admin123`)
6. **Deploy**
- Click **Create Web Service**
- Wait for build to complete (~2-3 minutes)
7. **Verify Deployment**
Check the deployment logs for:
β Connected to PostgreSQL database β Database tables initialized β Markdown Mash server running
Visit your app at the provided URL (e.g., `https://yourapp.onrender.com`)
---
### Alternative Deployment Options
#### Railway.app (All-in-One)
Railway can host both your app and database:
1. Connect GitHub repository
2. Add PostgreSQL service
3. Deploy automatically links DATABASE_URL
#### Heroku
1. Install Heroku Postgres add-on
2. Set `ADMIN_PASSWORD` config var
3. Deploy from GitHub
#### Self-Hosted / VPS
```bash
# Clone repository
git clone https://github.com/yourusername/MarkdownMash
cd MarkdownMash
# Install dependencies
npm install
# Create .env file
cat > .env << EOF
DATABASE_URL=postgresql://user:password@localhost:5432/markdownmash
ADMIN_PASSWORD=your_secure_password
PORT=3000
EOF
# Run with PM2 (process manager)
npm install -g pm2
pm2 start server.js --name markdownmash
pm2 save
Render Free Tier:
- Spins down after 15 minutes of inactivity
- First request after sleep takes ~30 seconds to wake up
- Perfect for classroom use, demos, and low-traffic deployments
Database Persistence:
- All quiz sessions, participants, and analytics are stored in PostgreSQL
- Data survives server restarts and redeployments
- You can view/export data through your database provider's dashboard
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | - | PostgreSQL connection string (Supabase pooler) |
ADMIN_PASSWORD |
No | admin123 |
Admin login password (used for initial setup only) |
PORT |
No | 3000 |
Server port (Render sets this automatically) |
If you are running a local PostgreSQL instance (e.g., via Docker), the default database is usually named postgres. You can connect to it using:
```env
DATABASE_URL=postgresql://postgres:yourpassword@localhost:5432/postgres
```
Note: The app is configured to automatically disable SSL for local development and enable it for production environments (like Render or Supabase) based on the NODE_ENV variable or the connection string.
# Run with auto-reload
npm run dev
# Simulate participants for testing
npm run simulate # 3 participants
npm run simulate 10 # 10 participantsView detailed insights from completed quiz sessions:
- Platform Overview: Total sessions, participants, average scores
- Question Difficulty: Automatic difficulty ratings (easy/medium/hard)
- Answer Distribution: See which options players chose
- Response Times: Track how quickly participants answered
- Performance Rankings: Leaderboard with scores and speed
- CSV Export: Download session data for Excel/spreadsheet analysis
Access via Admin Dashboard β Session History β View Analytics
markdown-mash/
βββ server.js # Express + Socket.IO server
βββ db.js # PostgreSQL database module
βββ package.json # Dependencies and scripts
βββ .env.example # Environment variables template
βββ render.yaml # Render.com deployment config
βββ sample-quiz.md # Example quiz
βββ test-simulation.js # Participant simulator for testing
βββ public/
βββ index.html # Landing page
βββ admin.html # Host dashboard with analytics
βββ play.html # Participant view (mobile-optimized)
βββ present.html # Presenter view (for screen sharing)
βββ css/
β βββ style.css # All styles
βββ js/
βββ admin.js # Admin client logic
βββ play.js # Participant client logic
βββ present.js # Presenter client logic
The app automatically creates these PostgreSQL tables:
- sessions: Quiz sessions with unique 6-character codes
- participants: Players who joined sessions (with scores)
- answers: Individual answer records (for analytics and response time tracking)
All data includes proper foreign keys and indexes for performance.
- No persistent user accounts (participants join per-session)
- No native image uploading (images must be hosted via external URL using standard Markdown
)
MIT













