A config-driven, static-site template for building interactive university course websites. Designed by Dr. Mohamed Mabrok to ensure a consistent professional "signature" across all courses. Originally derived from the Differential Equations course.
Live example: DE Course | This template: GitHub
- Architecture Overview
- File Structure
- Quick Start — Creating a New Course
- The Config File (
course-config.js) - Page-by-Page Guide
- Design System Reference
- Exam Generator — Adding Questions
- Deployment (GitHub Pages)
- Working with Claude / AI Assistants
- Technical Reference
The template follows a config-driven architecture. A single JavaScript file (course-config.js) holds all course-specific data — title, instructor info, chapters, topics, colors, exam mappings, and footer. Every HTML page reads from this config at load time, so you rarely need to edit the HTML structure itself.
course-config.js ←── THE source of truth
│
├── index.html (home page: hero, mind map, chapter cards)
├── chapter-template.html (copy per topic: theory, examples, practice)
├── exam-generator.html (randomized practice exams)
├── videos.html (video gallery)
└── why-study.html (motivational intro page)
styles.css ← shared design system (CSS custom properties, all components)
course.js ← shared utilities (KaTeX init, collapsibles, RK4 solver)
External CDN dependencies (no build step required):
- KaTeX 0.16.9 — LaTeX math rendering (
$...$inline,$$...$$display) - Plotly.js 2.27.0 — Interactive charts and visualizations (chapter pages only)
course-template/
│
├── course-config.js # ★ EDIT THIS FIRST — all course customization
│
├── styles.css # Shared CSS design system
│ - CSS custom properties (--primary, --accent, etc.)
│ - Navigation (fixed, frosted-glass)
│ - Content boxes (definition, theorem, example, warning, tip)
│ - Collapsible sections (3 patterns)
│ - Tables, quizzes, plots, responsive breakpoints
│
├── course.js # Shared JavaScript utilities
│ - KaTeX auto-render config & init
│ - toggleCollapsible(), togglePractice(), toggleContent()
│ - safeEval() — math expression evaluator
│ - rk4() — Runge-Kutta 4th order ODE solver
│ - shuffle() — Fisher-Yates array shuffler
│
├── index.html # Home page (auto-built from config)
│ - Nav bar, hero with instructor card
│ - SVG mind map (auto-generated from chapters)
│ - Chapter cards grid
│ - Chapter detail sections with topic cards
│
├── chapter-template.html # ★ COPY THIS for each topic page
│ - Sections: intro, theory, method, examples, visualizer, practice
│ - Sample Plotly chart, collapsible worked examples
│ - All CUSTOMIZE comments marked
│
├── exam-generator.html # Practice exam generator
│ - Chapter selection grid (from config)
│ - PROBLEMS[] array — add questions here
│ - Generates 5-question exams (MC + free response)
│ - Answer checking, explanations, print support
│
├── videos.html # Video lectures gallery
│ - Video cards with metadata/tags
│ - Coming-soon placeholders
│
├── why-study.html # "Why study this subject?" page
│ - Motivational sections with content boxes
│ - Applications grid, historical quotes
│ - All CUSTOMIZE comments marked
│
├── instructor.jpg # ★ REPLACE with your photo
├── avatar.svg # Fallback "MM" initials avatar
│
├── TEMPLATE-README.md # Extended reference (design patterns)
└── QUICKSTART.txt # One-page quick reference
Click "Use this template" on GitHub (or fork/clone), then rename it (e.g., Calc2, LinearAlgebra).
This is the only file you must edit. Change these fields:
const COURSE = {
code: "MATH 102", // Your course code
title: "Calculus II", // Full course title
brandName: "Calc 2", // Short name for nav logo
heroHighlight: "Calculus II", // Word(s) with gradient effect in hero
subtitle: "Integration techniques, sequences, series, and applications.",
instructor: {
name: "Dr. Mohamed Mabrok",
initials: "MM",
role: "Associate Professor",
department: "Mathematics & Statistics, Qatar University",
email: "m.a.mabrok@gmail.com",
photo: "instructor.jpg",
},
stats: [
{ num: "6", label: "Chapters" },
{ num: "30+", label: "Topics" },
{ num: "150+", label: "Problems" },
{ num: "Live", label: "Visualizations" },
],
chapters: [
{
id: "ch1",
title: "Integration Techniques",
shortTitle: "Integration",
description: "Beyond basic antiderivatives: substitution, parts, partial fractions, and trigonometric methods.",
tagline: "The art of finding antiderivatives",
status: "available",
topics: [
{
id: "ch1-substitution",
title: "1.1 — Substitution",
icon: "S",
description: "Reversing the chain rule for composition of functions.",
mathPreview: "\\int f(g(x))g'(x)\\,dx",
file: "ch1-substitution.html",
},
// ... more topics
],
},
// ... more chapters
],
connections: [
{ from: "ch1", to: "ch2", type: "prerequisite", label: "prerequisite" },
],
applications: "Area & Volume · Arc Length · Probability · Physics · Engineering",
};Drop your photo in the root folder. The fallback initials avatar (avatar.svg) displays automatically if the photo fails to load.
For each topic in your config, copy chapter-template.html:
cp chapter-template.html ch1-substitution.html
cp chapter-template.html ch1-integration-by-parts.html
# etc.Then edit each file — search for <!-- CUSTOMIZE --> comments to find every section that needs your content.
Open exam-generator.html and add questions to the PROBLEMS array (see Exam Generator section below).
Push to GitHub and enable GitHub Pages (Settings → Pages → Source: main branch).
Every field and what it controls:
| Field | Type | Used By | Description |
|---|---|---|---|
code |
string | index.html hero | Course code (e.g., "MATH 201") |
title |
string | index.html hero, mind map | Full course title |
subtitle |
string | index.html hero | One-line course description |
brandName |
string | index.html nav | Short name in top-left nav logo |
heroHighlight |
string | index.html hero | Word(s) that get gradient text effect |
instructor.name |
string | hero card, footer | Full name with title |
instructor.initials |
string | hero card fallback | 2-letter initials for avatar fallback |
instructor.role |
string | hero card | Academic title |
instructor.department |
string | hero card | Department and institution |
instructor.email |
string | hero card | Contact email (mailto link) |
instructor.photo |
string | hero card | Filename of photo in root folder |
stats[] |
array | hero stats bar | Each: { num: "5", label: "Chapters" } |
theme.* |
strings | CSS variables | Color hex codes for the design system |
chapterColors[] |
array | mind map, topic icons | Each: { main, light, gradient: [from, to] } |
chapters[] |
array | index.html, mind map | Chapter definitions (see below) |
chapters[].id |
string | anchor links | e.g., "ch1" — used as #ch1 anchor |
chapters[].title |
string | chapter card, detail | Full chapter title |
chapters[].shortTitle |
string | mind map box header | Shorter name for mind map |
chapters[].description |
string | chapter card, detail | 1-2 sentence description |
chapters[].tagline |
string | mind map box | Italicized phrase in mind map |
chapters[].status |
string | chapter card | "available" or "coming-soon" |
chapters[].topics[] |
array | detail section | Topic definitions (see below) |
topics[].id |
string | internal | Unique identifier |
topics[].title |
string | topic card | e.g., "1.1 — Substitution" |
topics[].icon |
string | topic card icon | Single letter shown in colored circle |
topics[].description |
string | topic card | One-line description |
topics[].mathPreview |
string | topic card | LaTeX string (no $ delimiters needed) |
topics[].file |
string | topic card link | Filename of the topic HTML page |
connections[] |
array | mind map arrows | { from, to, type, label } |
examChapters[] |
array | exam-generator.html | { ch, badge, color, title, topics } |
navLinks[] |
array | index.html nav | { label, href, active } |
footer.* |
object | all pages | courseName, year, instructor, department, institution |
whyStudy.* |
object | why-study.html | title, subtitle for hero |
videos.* |
object | videos.html | title, subtitle for hero |
applications |
string | mind map bottom bar | Dot-separated list of applications |
Auto-built from config. You should not need to edit this file unless you want to change the hero SVG visualization or the layout structure.
What it generates automatically:
- Navigation bar with brand name and links
- Hero section with course title, subtitle, instructor card, and stats bar
- SVG mind map showing chapters, connections, and prerequisite flow
- Chapter cards grid with status badges and topic tags
- Chapter detail sections with clickable topic cards (with math previews)
- Footer
To customize the hero SVG: Edit the <svg class="hero-viz"> element directly in index.html. This is the animated graph on the right side of the hero — replace the sample curves with something relevant to your course.
Copy this for every topic. Each copy becomes a standalone lesson page.
Sections (in order):
- Navigation — Fixed top bar with logo + in-page section links
- #intro — Title, subtitle, learning objectives checklist, definition box
- #theory — Theorem box with proof/derivation in collapsible
- #method — Step-by-step numbered procedure
- #examples — Worked examples with collapsible step-by-step solutions
- #visualizer — Interactive Plotly.js chart (sample included)
- #practice — Practice problems with collapsible answers
How to edit: Search for <!-- CUSTOMIZE in the file — every editable section is marked. There are ~20 CUSTOMIZE comments guiding you.
Navigation links: Edit the <nav> section to add links to sibling topics (e.g., 1.1, 1.2, 1.3) and in-page anchors (#intro, #theory, etc.).
Adding a Plotly chart: The template includes a sample sine/cosine chart. Replace the Plotly.newPlot() call in the <script> section with your own data and layout.
Reads chapter info from COURSE.examChapters to build the selection grid. Students select chapters, click "Generate", and get a randomized 5-question exam (2-3 MC + 2-3 free response).
Chapter cards are auto-built from config. Questions live in the PROBLEMS array inside the <script> tag — see the dedicated section below.
Template for a video lectures page. Edit directly to add your video files or embed URLs.
A "Chapter 0" style page that motivates students. Has sections for real-world applications, historical context, and course positioning. Edit the content directly — search for <!-- CUSTOMIZE --> comments.
All colors are defined as CSS variables in styles.css and can be overridden via course-config.js theme settings:
--primary: #2563eb; /* Blue — headings, links, primary buttons */
--primary-light: #dbeafe; /* Light blue — definition boxes, hover states */
--primary-dark: #1e40af; /* Dark blue — topic tags */
--accent: #7c3aed; /* Purple — h2 headings, theorem boxes */
--accent-light: #ede9fe; /* Light purple — theorem box backgrounds */
--success: #059669; /* Green — tip boxes, success states */
--warning: #d97706; /* Orange — warning boxes */
--danger: #dc2626; /* Red — danger boxes, incorrect answers */
--bg: #f8fafc; /* Page background */
--card: #ffffff; /* Card/box background */
--text: #1e293b; /* Body text */
--text-muted: #64748b; /* Secondary text */
--border: #e2e8f0; /* Borders, dividers */
--radius: 12px; /* Border radius */Five colored box types for structuring content:
<!-- Blue — definitions, key concepts -->
<div class="definition-box">
<h3>Definition: Integration by Parts</h3>
<p>$$\int u\,dv = uv - \int v\,du$$</p>
</div>
<!-- Purple — theorems, important results -->
<div class="theorem-box">
<h3>Theorem: Fundamental Theorem of Calculus</h3>
<p>If $F'(x) = f(x)$, then $\int_a^b f(x)\,dx = F(b) - F(a)$.</p>
</div>
<!-- Light blue — worked examples -->
<div class="example-box">
<h3>Example 1</h3>
<p>Evaluate $\int x e^x\,dx$.</p>
</div>
<!-- Orange — common mistakes, cautions -->
<div class="warning-box">
<h3>Common Mistake</h3>
<p>Don't forget the constant of integration!</p>
</div>
<!-- Green — tips, shortcuts -->
<div class="tip-box">
<h3>Pro Tip</h3>
<p>Use LIATE to choose $u$ in integration by parts.</p>
</div>Alternative box pattern (with label):
<div class="box-primary"><div class="box-label">KEY CONCEPT</div><p>Content</p></div>
<div class="box-accent"><div class="box-label">THEOREM</div><p>Content</p></div>
<div class="box-success"><div class="box-label">TIP</div><p>Content</p></div>
<div class="box-warning"><div class="box-label">CAUTION</div><p>Content</p></div>
<div class="box-danger"><div class="box-label">ERROR</div><p>Content</p></div>Three patterns available:
Pattern 1: Blue outlined toggle (most common — used for solutions, proofs)
<div class="collapsible">
<button class="collapsible-toggle" onclick="toggleCollapsible(this)">
Show Solution <span class="arrow">▶</span>
</button>
<div class="collapsible-content">
<p>Step 1: $$\int x e^x\,dx$$</p>
<p>Step 2: Let $u = x$, $dv = e^x\,dx$...</p>
</div>
</div>Pattern 2: White card toggle (used for worked examples)
<button class="collapsible-header" onclick="toggleCollapsible(this)">
Worked Example: Finding the Area
<span class="collapsible-arrow">▼</span>
</button>
<div class="collapsible-content">
<p>Solution goes here...</p>
</div>Pattern 3: Purple header toggle (used for practice problems)
<div class="example-item">
<div class="example-header" onclick="togglePractice(this)">
<span>Practice Problem 1</span>
<span class="toggle-icon">▼</span>
</div>
<div class="example-content">
<p>Solution...</p>
</div>
</div>All pages use the same nav structure:
<nav>
<div class="logo"><a href="index.html">Course Name</a></div>
<div class="nav-links">
<a href="index.html">Home</a>
<a href="#intro" class="active">Intro</a>
<a href="#theory">Theory</a>
<!-- more links -->
</div>
</nav>- Inline math:
$f(x) = x^2$renders as inline formula - Display math:
$$\int_0^1 f(x)\,dx = \frac{1}{3}$$renders as centered block - In collapsibles: KaTeX auto-re-renders when a collapsible opens (handled by
course.js) - Escape in JS strings: Use
\\frac,\\int, etc. (double backslash)
<table>
<thead><tr><th>Method</th><th>When to Use</th><th>Example</th></tr></thead>
<tbody>
<tr><td>Substitution</td><td>Composition</td><td>$\int 2x\cos(x^2)\,dx$</td></tr>
</tbody>
</table>Plotly.newPlot('myPlot', [{
x: xData, y: yData,
type: 'scatter', mode: 'lines',
name: 'f(x)',
line: { color: '#2563eb', width: 2.5 }
}], {
title: 'Chart Title',
paper_bgcolor: 'rgba(0,0,0,0)',
plot_bgcolor: 'rgba(0,0,0,0)',
font: { family: 'Segoe UI, system-ui, sans-serif' },
margin: { t: 50, r: 30, b: 50, l: 60 },
}, { responsive: true });Use .plot-container for single charts, .plots-grid for side-by-side:
<div class="plot-container"><div id="myPlot" style="width:100%;height:450px;"></div></div>
<div class="plots-grid">
<div id="plot1" class="plot-container"></div>
<div id="plot2" class="plot-container"></div>
</div>All questions go in the PROBLEMS array inside exam-generator.html:
Multiple Choice:
{
ch: 1, // Chapter number (matches examChapters[].ch)
topic: "Integration by Parts", // Topic label shown on question card
type: "mc", // "mc" for multiple choice
statement: "Evaluate $\\int x e^x\\,dx$", // Question (supports KaTeX)
choices: [
"$$xe^x - e^x + C$$", // Choice A (index 0)
"$$xe^x + e^x + C$$", // Choice B (index 1)
"$$x^2 e^x + C$$", // Choice C (index 2)
"$$e^x + C$$" // Choice D (index 3)
],
correct: 0, // 0-indexed correct answer
explanation: "Using IBP with $u=x$, $dv=e^x dx$: $\\int xe^x dx = xe^x - \\int e^x dx = xe^x - e^x + C$."
},Free Response:
{
ch: 1,
topic: "Substitution",
type: "free", // "free" for free response
statement: "Evaluate $\\int \\frac{2x}{1+x^2}\\,dx$.",
solution: [
{ title: "Step 1: Choose substitution", text: "Let $u = 1 + x^2$, so $du = 2x\\,dx$" },
{ title: "Step 2: Transform integral", text: "$$\\int \\frac{du}{u}$$" },
{ title: "Step 3: Integrate", text: "$$\\ln|u| + C$$" },
{ title: "Step 4: Back-substitute", text: "$$\\ln|1+x^2| + C = \\ln(1+x^2) + C$$" },
],
answer: "$$\\ln(1+x^2) + C$$"
},- Aim for 15-25 questions per chapter for good variety
- Mix 60% MC and 40% free response
- Cover all topics within each chapter
- Include a range of difficulties (basic recall → multi-step problem solving)
- The exam generator picks 5 random questions from selected chapters
- Questions are shuffled each time, so duplicates are rare with a large pool
- Student selects 1+ chapters from the grid
- Clicks "Generate Practice Exam"
- JavaScript filters
PROBLEMSby selected chapter numbers - Shuffles and picks 5 questions
- Splits into ~3 MC + ~2 free response (adjusts based on availability)
- Renders question cards with answer checking and reveal buttons
- "Reveal All" shows all answers; "Print" creates a clean printable version
- Push your customized template to GitHub
- Go to Settings → Pages
- Under "Source", select Deploy from a branch
- Choose main branch, / (root) folder
- Click Save
- Your site will be live at
https://your-username.github.io/repo-name/
Custom domain: Add a CNAME file with your domain, then configure DNS.
Bypassing CDN cache for testing: Use rawcdn.githack.com with a specific commit hash:
https://rawcdn.githack.com/Minds-R-Lab/repo-name/COMMIT_HASH/index.html
This template is designed to work well with Claude and similar AI coding assistants. When starting a new course with Claude:
I have a course website template at https://github.com/Minds-R-Lab/course-template.
I need to create a new course for [COURSE NAME]. Please:
1. Clone the template repo
2. Edit course-config.js with my course details:
- Code: [MATH XXX]
- Title: [Full Title]
- Chapters: [list your chapters and topics]
3. Create chapter pages from chapter-template.html for each topic
4. Build the exam question pool (aim for 15+ questions per chapter)
5. Push to GitHub and enable Pages
- Config-driven: Edit
course-config.jsfirst — index.html reads from it - Nav pattern: All pages use
.logodiv +.nav-linksdiv (the "logo-div" pattern) - Math: KaTeX with
$...$inline and$$...$$display; in JS strings use\\for backslash - Content boxes:
.definition-box,.theorem-box,.example-box,.warning-box,.tip-box - Collapsibles:
onclick="toggleCollapsible(this)"with.collapsible-toggle+.collapsible-content - Plots: Plotly.js in
.plot-container(single) or.plots-grid(side-by-side) - Exam questions: Add to
PROBLEMS[]array in exam-generator.html with{ch, topic, type, statement, choices/solution, correct/answer, explanation} - Chapter pages: Copy
chapter-template.html, search for<!-- CUSTOMIZEcomments - CSS variables:
--primary,--accent,--success,--warning,--dangerwith-lightvariants - Shared JS functions:
initKaTeX(),toggleCollapsible(),togglePractice(),rk4(),safeEval(),shuffle()
Modern browsers (Chrome, Firefox, Safari, Edge). Uses CSS custom properties, backdrop-filter, and ES6 features.
| Library | Version | CDN | Used For |
|---|---|---|---|
| KaTeX | 0.16.9 | cdnjs.cloudflare.com | Math rendering |
| Plotly.js | 2.27.0 | cdnjs.cloudflare.com | Interactive charts |
| Function | Signature | Description |
|---|---|---|
initKaTeX(el?) |
(HTMLElement?) → void |
Render math in element (defaults to document.body) |
toggleCollapsible(btn) |
(HTMLElement) → void |
Toggle .collapsible-content next to button |
togglePractice(header) |
(HTMLElement) → void |
Toggle practice problem content |
toggleContent(btn) |
(HTMLElement) → void |
Toggle .toggle-content next to button |
safeEval(expr, x, y) |
(string, number, number?) → number |
Evaluate math expression safely |
rk4(f, x0, y0, xf, h?) |
(Function, ...) → [number[], number[]] |
RK4 ODE solver, returns [xs, ys] |
shuffle(arr) |
(Array) → Array |
Fisher-Yates shuffle (returns new array) |
- Desktop: > 768px — full layout, side-by-side grids
- Mobile: ≤ 768px — single column, hero text centered, nav wraps
The exam generator includes print-optimized CSS that hides navigation, buttons, and backgrounds for clean printed exams.
MIT — Free to use for any educational purpose.
Created by Dr. Mohamed Mabrok — Mathematics & Statistics, Qatar University