~/usmle-study-guide/build_pdf.py
#!/usr/bin/env python3
"""
USMLE High-Yield Study Guide PDF Builder
Uses ReportLab for rich formatting
"""
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
from reportlab.lib.colors import HexColor, Color
import os
# ── Color palette ──────────────────────────────────────────────────────────────
NAVY = HexColor("#1A2B5F")
TEAL = HexColor("#0B7A75")
AMBER = HexColor("#E07B00")
CORAL = HexColor("#C0392B")
LIGHT_BLUE = HexColor("#EBF4FA")
LIGHT_TEAL = HexColor("#E0F7F6")
LIGHT_AMBER= HexColor("#FFF3E0")
LIGHT_CORAL= HexColor("#FDECEA")
LIGHT_GRAY = HexColor("#F5F5F5")
MID_GRAY = HexColor("#CCCCCC")
DARK_GRAY = HexColor("#444444")
WHITE = colors.white
BLACK = colors.black
GREEN = HexColor("#1B6B35")
LIGHT_GREEN= HexColor("#E8F5E9")
PURPLE = HexColor("#6A0DAD")
LIGHT_PURPLE=HexColor("#F3E5F5")
OUTPUT_PATH = "/tmp/workspace/usmle-study-guide/USMLE_High_Yield_Study_Guide.pdf"
# ── Document setup ─────────────────────────────────────────────────────────────
def build_styles():
base = getSampleStyleSheet()
styles = {}
styles['cover_title'] = ParagraphStyle(
'cover_title', fontName='Helvetica-Bold', fontSize=32,
textColor=WHITE, alignment=TA_CENTER, leading=38, spaceAfter=8
)
styles['cover_sub'] = ParagraphStyle(
'cover_sub', fontName='Helvetica', fontSize=14,
textColor=HexColor("#AEDFF7"), alignment=TA_CENTER, leading=20, spaceAfter=6
)
styles['cover_tag'] = ParagraphStyle(
'cover_tag', fontName='Helvetica-Oblique', fontSize=11,
textColor=HexColor("#FFD580"), alignment=TA_CENTER, leading=16
)
styles['section_header'] = ParagraphStyle(
'section_header', fontName='Helvetica-Bold', fontSize=17,
textColor=WHITE, alignment=TA_LEFT, leading=22,
spaceBefore=4, spaceAfter=6, leftIndent=0
)
styles['topic_header'] = ParagraphStyle(
'topic_header', fontName='Helvetica-Bold', fontSize=13,
textColor=NAVY, alignment=TA_LEFT, leading=17,
spaceBefore=10, spaceAfter=4
)
styles['sub_header'] = ParagraphStyle(
'sub_header', fontName='Helvetica-Bold', fontSize=11,
textColor=TEAL, alignment=TA_LEFT, leading=14,
spaceBefore=7, spaceAfter=3
)
styles['body'] = ParagraphStyle(
'body', fontName='Helvetica', fontSize=9.5,
textColor=DARK_GRAY, alignment=TA_JUSTIFY, leading=14,
spaceBefore=2, spaceAfter=2, leftIndent=4
)
styles['bullet'] = ParagraphStyle(
'bullet', fontName='Helvetica', fontSize=9.5,
textColor=DARK_GRAY, alignment=TA_LEFT, leading=13,
spaceBefore=1, spaceAfter=1, leftIndent=14, bulletIndent=4,
bulletText='•'
)
styles['sub_bullet'] = ParagraphStyle(
'sub_bullet', fontName='Helvetica', fontSize=9,
textColor=DARK_GRAY, alignment=TA_LEFT, leading=12,
spaceBefore=0, spaceAfter=0, leftIndent=28, bulletIndent=18,
bulletText='–'
)
styles['pearl'] = ParagraphStyle(
'pearl', fontName='Helvetica-Bold', fontSize=9.5,
textColor=AMBER, alignment=TA_LEFT, leading=13,
spaceBefore=2, spaceAfter=2, leftIndent=8
)
styles['mnemonic'] = ParagraphStyle(
'mnemonic', fontName='Helvetica-BoldOblique', fontSize=10,
textColor=PURPLE, alignment=TA_LEFT, leading=14,
spaceBefore=2, spaceAfter=2, leftIndent=8
)
styles['warning'] = ParagraphStyle(
'warning', fontName='Helvetica-Bold', fontSize=9.5,
textColor=CORAL, alignment=TA_LEFT, leading=13,
spaceBefore=2, spaceAfter=2, leftIndent=8
)
styles['table_header'] = ParagraphStyle(
'table_header', fontName='Helvetica-Bold', fontSize=8.5,
textColor=WHITE, alignment=TA_CENTER, leading=11
)
styles['table_cell'] = ParagraphStyle(
'table_cell', fontName='Helvetica', fontSize=8,
textColor=DARK_GRAY, alignment=TA_LEFT, leading=11
)
styles['table_cell_bold'] = ParagraphStyle(
'table_cell_bold', fontName='Helvetica-Bold', fontSize=8,
textColor=DARK_GRAY, alignment=TA_LEFT, leading=11
)
styles['page_num'] = ParagraphStyle(
'page_num', fontName='Helvetica', fontSize=8,
textColor=MID_GRAY, alignment=TA_CENTER
)
styles['highlight_body'] = ParagraphStyle(
'highlight_body', fontName='Helvetica', fontSize=9.5,
textColor=DARK_GRAY, alignment=TA_LEFT, leading=14,
spaceBefore=2, spaceAfter=2, leftIndent=10
)
return styles
# ── Helper builders ─────────────────────────────────────────────────────────────
def section_banner(title, color=NAVY, styles=None):
"""Returns a full-width colored banner with white title text."""
data = [[Paragraph(title, styles['section_header'])]]
t = Table(data, colWidths=[7.0*inch])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), color),
('TOPPADDING', (0,0), (-1,-1), 8),
('BOTTOMPADDING',(0,0), (-1,-1), 8),
('LEFTPADDING', (0,0), (-1,-1), 12),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('ROUNDEDCORNERS', [4]),
]))
return t
def pearl_box(text, styles, color=LIGHT_AMBER, border=AMBER, label="⭐ USMLE PEARL"):
full = f"<b>{label}:</b> {text}"
data = [[Paragraph(full, styles['pearl'])]]
t = Table(data, colWidths=[6.8*inch])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), color),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LINEAFTER', (0,0), (0,-1), 4, border),
('BOX', (0,0), (-1,-1), 0.5, border),
]))
return t
def mnemonic_box(text, styles):
full = f"🧠 MNEMONIC: {text}"
data = [[Paragraph(full, styles['mnemonic'])]]
t = Table(data, colWidths=[6.8*inch])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), LIGHT_PURPLE),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('BOX', (0,0), (-1,-1), 0.5, PURPLE),
]))
return t
def warning_box(text, styles):
full = f"⚠️ WATCH OUT: {text}"
data = [[Paragraph(full, styles['warning'])]]
t = Table(data, colWidths=[6.8*inch])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), LIGHT_CORAL),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('BOX', (0,0), (-1,-1), 0.5, CORAL),
]))
return t
def info_box(text, styles):
data = [[Paragraph(text, styles['highlight_body'])]]
t = Table(data, colWidths=[6.8*inch])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), LIGHT_BLUE),
('LEFTPADDING', (0,0), (-1,-1), 10),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LINEBEFORE', (0,0), (0,-1), 4, TEAL),
('BOX', (0,0), (-1,-1), 0.5, TEAL),
]))
return t
def two_col_table(headers, rows, styles, col_widths=None):
"""Generic styled table."""
if col_widths is None:
n = len(headers)
col_widths = [7.0*inch / n] * n
table_data = [[Paragraph(h, styles['table_header']) for h in headers]]
for row in rows:
table_data.append([Paragraph(str(c), styles['table_cell']) for c in row])
t = Table(table_data, colWidths=col_widths, repeatRows=1)
cmd = [
('BACKGROUND', (0,0), (-1,0), NAVY),
('GRID', (0,0), (-1,-1), 0.4, MID_GRAY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_GRAY]),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 5),
('RIGHTPADDING', (0,0), (-1,-1), 5),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
]
t.setStyle(TableStyle(cmd))
return t
def sp(n=1):
return Spacer(1, n * 4)
def hr(styles):
return HRFlowable(width="100%", thickness=0.5, color=MID_GRAY, spaceAfter=4, spaceBefore=4)
# ── Page templates ─────────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# Footer
canvas.setFont('Helvetica', 7.5)
canvas.setFillColor(MID_GRAY)
canvas.drawString(inch*0.75, 0.45*inch, "USMLE High-Yield Study Guide")
canvas.drawRightString(letter[0] - inch*0.75, 0.45*inch, f"Page {doc.page}")
canvas.setStrokeColor(MID_GRAY)
canvas.setLineWidth(0.3)
canvas.line(inch*0.75, 0.55*inch, letter[0]-inch*0.75, 0.55*inch)
canvas.restoreState()
def on_cover(canvas, doc):
canvas.saveState()
# Full navy background
canvas.setFillColor(NAVY)
canvas.rect(0, 0, letter[0], letter[1], fill=1, stroke=0)
# Teal accent bar at top
canvas.setFillColor(TEAL)
canvas.rect(0, letter[1]-0.5*inch, letter[0], 0.5*inch, fill=1, stroke=0)
# Amber bottom bar
canvas.setFillColor(AMBER)
canvas.rect(0, 0, letter[0], 0.35*inch, fill=1, stroke=0)
canvas.restoreState()
# ── Content builders ───────────────────────────────────────────────────────────
def build_cover(styles):
story = []
story.append(Spacer(1, 2.0*inch))
story.append(Paragraph("USMLE HIGH-YIELD", styles['cover_title']))
story.append(Paragraph("STUDY GUIDE", styles['cover_title']))
story.append(Spacer(1, 0.2*inch))
story.append(HRFlowable(width="60%", thickness=2, color=TEAL, spaceAfter=12, hAlign='CENTER'))
story.append(Paragraph("Cell Biology · Biochemistry · Neuroscience", styles['cover_sub']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph(
"Plasma Membrane • Transporters • GLUTs • Glycolysis • TCA • PPP\n"
"Malate-Aspartate Shuttle • ROS Neutralization • Myelin & Glia\n"
"Axonal Transport • Synapses • Neurotransmitters • GPCR Signaling",
styles['cover_tag']
))
story.append(Spacer(1, 0.5*inch))
story.append(HRFlowable(width="40%", thickness=1, color=AMBER, spaceAfter=12, hAlign='CENTER'))
story.append(Paragraph("High-Yield Facts • Mnemonics • Clinical Pearls • USMLE Traps", styles['cover_sub']))
story.append(PageBreak())
return story
def build_plasma_membrane(styles):
s = styles
story = []
story.append(section_banner("TOPIC 1: PLASMA MEMBRANE", NAVY, s))
story.append(sp(2))
story.append(Paragraph("Composition", s['topic_header']))
story.append(info_box(
"The plasma membrane is 7.5–10 nm thick. Composition: <b>55% proteins, 25% phospholipids, "
"13% cholesterol, 4% other lipids, 3% carbohydrates</b>. "
"Carbohydrates are <b>always on the extracellular face only</b> (glycoproteins + glycolipids = glycocalyx).",
s
))
story.append(sp(2))
story.append(Paragraph("Three Core Lipids", s['sub_header']))
rows = [
["Phospholipids", "Most abundant; asymmetric distribution across leaflets"],
["Sphingolipids", "Abundant in nerve cells; form lipid rafts; signal transduction"],
["Cholesterol", "Regulates fluidity & permeability; buffers against temperature extremes"],
]
story.append(two_col_table(["Lipid", "Key Role"], rows, s, [2.0*inch, 5.0*inch]))
story.append(sp(2))
story.append(Paragraph("Membrane Asymmetry", s['sub_header']))
rows2 = [
["Outer Leaflet", "Phosphatidylcholine (PC), Sphingomyelin, Glycolipids, Cholesterol"],
["Inner Leaflet", "Phosphatidylserine (PS), Phosphatidylethanolamine (PE), Phosphatidylinositol (PI)"],
]
story.append(two_col_table(["Leaflet", "Lipids Present"], rows2, s, [2.0*inch, 5.0*inch]))
story.append(sp(1))
story.append(pearl_box(
"Phosphatidylserine (PS) normally on inner leaflet. Flipping to outer leaflet = signal for "
"<b>apoptosis</b> (macrophage recognition) AND activates the <b>coagulation cascade</b>.",
s
))
story.append(sp(2))
story.append(Paragraph("Membrane Proteins", s['sub_header']))
rows3 = [
["Integral (transmembrane)", "Span entire bilayer; form channels, carriers, receptors; need detergent to extract"],
["Peripheral", "Attached to one surface; non-covalent; e.g. spectrin (RBC cytoskeleton)"],
]
story.append(two_col_table(["Type", "Key Features"], rows3, s, [2.2*inch, 4.8*inch]))
story.append(sp(2))
story.append(Paragraph("Fluidity Modifiers", s['sub_header']))
rows4 = [
["Unsaturated fatty acids (double bonds/kinks)", "↑ Fluidity"],
["Saturated fatty acids (straight chains, pack tightly)", "↓ Fluidity"],
["Short-chain fatty acids", "↑ Fluidity"],
["Cholesterol", "Buffer: prevents too-fluid at high temp; too-rigid at low temp"],
]
story.append(two_col_table(["Factor", "Effect on Fluidity"], rows4, s, [4.0*inch, 3.0*inch]))
story.append(sp(2))
story.append(Paragraph("Permeability Rules", s['sub_header']))
story.append(Paragraph("Freely cross (no transporter): O₂, CO₂, N₂, alcohol, steroid hormones, small nonpolar molecules, water (partial)", s['bullet']))
story.append(Paragraph("Need a transporter: glucose, amino acids, ions (Na⁺, K⁺, Ca²⁺, Cl⁻), large polar molecules", s['bullet']))
story.append(Paragraph("Cannot cross: proteins, nucleic acids, large charged molecules", s['bullet']))
story.append(sp(2))
story.append(warning_box("ABO blood group antigens are GLYCOLIPIDS on the RBC surface (not glycoproteins). MHC molecules are glycoproteins.", s))
story.append(sp(3))
return story
def build_transporters(styles):
s = styles
story = []
story.append(section_banner("TOPIC 2: MEMBRANE TRANSPORTERS", TEAL, s))
story.append(sp(2))
story.append(Paragraph("Overview: Passive vs. Active Transport", s['topic_header']))
rows = [
["Simple Diffusion", "No", "No", "Down gradient", "O₂, CO₂, steroids, EtOH"],
["Facilitated Diffusion", "Yes (channel or carrier)", "No", "Down gradient", "Glucose (GLUTs), H₂O (AQP)"],
["Primary Active", "Yes (pump/ATPase)", "Yes (ATP)", "Against gradient", "Na⁺/K⁺-ATPase, SERCA, H⁺/K⁺-ATPase"],
["Secondary Active", "Yes (cotransporter)", "No (uses Na⁺ gradient)", "Against gradient (solute)", "SGLTs, Na⁺/H⁺ exchanger"],
]
story.append(two_col_table(
["Type", "Protein Required?", "Direct ATP?", "Direction", "Examples"],
rows, s, [1.6*inch, 1.6*inch, 1.1*inch, 1.3*inch, 1.4*inch]
))
story.append(sp(2))
story.append(Paragraph("Na⁺/K⁺-ATPase — THE Most Tested Pump", s['sub_header']))
story.append(info_box(
"<b>Pumps 3 Na⁺ OUT and 2 K⁺ IN</b> per ATP hydrolyzed. Electrogenic (net positive charge out). "
"Maintains resting membrane potential and Na⁺ gradient for secondary active transport. "
"<b>Inhibited by: ouabain, digoxin (cardiac glycosides)</b>.",
s
))
story.append(pearl_box(
"Digoxin inhibits Na⁺/K⁺-ATPase → intracellular Na⁺ ↑ → Na⁺/Ca²⁺ exchanger works less → "
"intracellular Ca²⁺ ↑ → increased cardiac contractility. Used in heart failure + atrial fibrillation.",
s
))
story.append(sp(2))
story.append(Paragraph("Key Transporters for USMLE", s['sub_header']))
rows2 = [
["Na⁺/K⁺-ATPase", "All cells", "3 Na⁺ out, 2 K⁺ in", "Digoxin, ouabain inhibit"],
["SERCA", "SR of muscle", "Ca²⁺ into SR", "Defective in heart failure"],
["H⁺/K⁺-ATPase", "Gastric parietal cells", "H⁺ out → acid secretion", "PPIs (omeprazole) block irreversibly"],
["SGLT1", "Small intestine", "Na⁺ + glucose/galactose", "Glucose-galactose malabsorption if mutated"],
["SGLT2", "Proximal tubule", "Na⁺ + glucose reabsorption", "SGLT2 inhibitors: T2DM treatment"],
["P-glycoprotein (MDR1)", "Many tumors, BBB, gut", "Pumps drugs out", "Multidrug resistance in cancer"],
["Aquaporin-2 (AQP2)", "Collecting duct", "Water reabsorption", "Regulated by ADH/vasopressin"],
]
story.append(two_col_table(
["Transporter", "Location", "Substrate/Action", "Clinical Relevance"],
rows2, s, [1.5*inch, 1.5*inch, 2.0*inch, 2.0*inch]
))
story.append(sp(2))
story.append(mnemonic_box("Secondary active transport: the Na⁺ gradient is the 'battery' – charged by Na⁺/K⁺-ATPase (uses ATP), then SGLT/NHE run off this battery (no direct ATP needed).", s))
story.append(sp(2))
story.append(pearl_box(
"SGLT2 inhibitors (empagliflozin, dapagliflozin, canagliflozin): block Na⁺/glucose co-transport in proximal tubule → glucosuria → lower blood glucose. "
"Also reduce cardiovascular mortality and renal disease progression in T2DM.",
s
))
story.append(sp(3))
return story
def build_gluts(styles):
s = styles
story = []
story.append(section_banner("TOPIC 3: GLUCOSE TRANSPORTERS (GLUTs)", TEAL, s))
story.append(sp(2))
story.append(info_box(
"All GLUTs are <b>facilitated diffusion</b> transporters — bidirectional, no ATP, cannot concentrate glucose above extracellular levels. "
"They show saturation kinetics (Km, Vmax).",
s
))
story.append(sp(2))
rows = [
["GLUT1", "Low (~1 mM)", "RBC, brain (BBB), placenta, basal all cells",
"NOT insulin-regulated; constitutive", "GLUT1 deficiency: seizures, low CSF glucose → ketogenic diet"],
["GLUT2", "High (~15–20 mM)", "Liver, pancreatic β-cells, intestine (enterocytes), kidney proximal tubule",
"NOT insulin-regulated; glucose SENSOR", "Fanconi-Bickel syndrome (GLUT2 mutation): glycogen accumulation in liver/kidney"],
["GLUT3", "Very low (~1.4 mM)", "Neurons (highest affinity — neurons always get glucose first)",
"NOT insulin-regulated; constitutive", "Ensures neuron glucose supply even when blood glucose is low"],
["GLUT4", "~5 mM", "Skeletal muscle, adipose tissue, cardiac muscle",
"INSULIN-DEPENDENT — stored in vesicles, translocates to membrane on insulin signal", "Impaired translocation in Type 2 DM (insulin resistance); exercise also triggers via AMPK"],
["GLUT5", "~6 mM (fructose)", "Small intestine (mainly), spermatocytes",
"Transports FRUCTOSE ONLY — no glucose", "Hereditary fructose intolerance ≠ GLUT5; GLUT5 mutation = fructose malabsorption (diarrhea)"],
]
story.append(two_col_table(
["GLUT", "Km", "Location", "Regulation", "Clinical Relevance"],
rows, s, [0.6*inch, 0.9*inch, 1.7*inch, 2.0*inch, 1.8*inch]
))
story.append(sp(2))
story.append(mnemonic_box(
'"1 brain (always on), 2 liver-sensor, 3 neurons (highest affinity), 4 muscle (insulin-dependent), 5 fructose-only"\n'
'GLUT4 needs Insulin to Translocate — "G4 = Gym (muscle) + Insulin"',
s
))
story.append(sp(2))
story.append(Paragraph("GLUT4 Signaling Cascade (HIGH YIELD)", s['sub_header']))
story.append(info_box(
"<b>Insulin → Insulin Receptor (RTK) → auto-phosphorylation Tyr → IRS-1 → PI3K → PIP3 → "
"PDK1 → Akt (PKB) → GLUT4 vesicle fusion with plasma membrane → glucose uptake ↑</b>. "
"Exercise activates GLUT4 via <b>AMPK pathway</b>, independent of insulin.",
s
))
story.append(sp(3))
return story
def build_carb_metabolism(styles):
s = styles
story = []
story.append(section_banner("TOPIC 4: CARBOHYDRATE METABOLISM", NAVY, s))
story.append(sp(2))
# Glycolysis
story.append(Paragraph("Glycolysis (Cytosol)", s['topic_header']))
story.append(info_box(
"10-step pathway: Glucose → 2 Pyruvate + <b>2 net ATP</b> + 2 NADH (at step 6). "
"Occurs in cytosol. ALL cells use glycolysis.",
s
))
story.append(sp(1))
story.append(Paragraph("3 Irreversible (Regulated) Steps:", s['sub_header']))
rows = [
["Step 1", "Hexokinase / Glucokinase", "Glucose → Glucose-6-P",
"HK: low Km, product-inhibited; GK: high Km, liver/β-cells, induced by insulin", "ATP consumed"],
["Step 3", "PFK-1 ★ RATE-LIMITING", "Fructose-6-P → Fructose-1,6-BP",
"Activated: AMP, ADP, F-2,6-BP; Inhibited: ATP, citrate", "ATP consumed"],
["Step 10", "Pyruvate kinase", "PEP → Pyruvate",
"Activated: F-1,6-BP (feedforward); Inhibited: ATP, alanine; Deficiency = hemolytic anemia", "ATP generated"],
]
story.append(two_col_table(
["Step", "Enzyme", "Reaction", "Regulation", "Energy"],
rows, s, [0.5*inch, 1.6*inch, 1.5*inch, 2.6*inch, 0.8*inch]
))
story.append(sp(1))
story.append(mnemonic_box('"PFK-1 is the GATEKEEPER of glycolysis: AMP opens the gate (need energy), ATP closes it (enough energy), F-2,6-BP is the master key (insulin signal)."', s))
story.append(sp(2))
# PDH
story.append(Paragraph("Pyruvate Dehydrogenase (PDH) Complex — Cytosol → Mitochondria Bridge", s['sub_header']))
story.append(info_box(
"Converts Pyruvate → Acetyl-CoA + NADH + CO₂. Location: <b>mitochondrial matrix</b>. "
"<b>Required cofactors (ALL B vitamins):</b> Thiamine (B1), FAD (B2), NAD⁺ (B3), CoA (B5), Lipoic acid. "
"<b>Inhibited by:</b> Acetyl-CoA, NADH, ATP (product inhibition). "
"<b>Activated by:</b> NAD⁺, AMP, Ca²⁺.",
s
))
story.append(mnemonic_box('"The Fairy Needs Candy Licorice" = Thiamine (B1), FAD (B2), NAD+ (B3), CoA (B5), Lipoic acid', s))
story.append(warning_box(
"PDH deficiency / Thiamine (B1) deficiency → cannot convert pyruvate to Acetyl-CoA → "
"pyruvate → lactate + alanine → LACTIC ACIDOSIS. Seen in Wernicke's encephalopathy (B1 deficiency). "
"Treat with thiamine BEFORE giving glucose IV (giving glucose first depletes B1 further!).",
s
))
story.append(sp(2))
# TCA
story.append(Paragraph("TCA Cycle / Krebs Cycle (Mitochondrial Matrix)", s['topic_header']))
story.append(info_box(
"Per glucose: 2 acetyl-CoA → <b>6 NADH + 2 FADH₂ + 2 GTP</b>. "
"Each NADH → 2.5 ATP; each FADH₂ → 1.5 ATP. "
"CO₂ is released at: isocitrate dehydrogenase step AND α-ketoglutarate dehydrogenase step.",
s
))
rows_tca = [
["Citrate synthase", "OAA + Acetyl-CoA → Citrate", "Inhibited by citrate, NADH, ATP"],
["Isocitrate dehydrogenase ★", "Isocitrate → α-KG + CO₂ (RATE-LIMITING)", "Inhibited by ATP, NADH; Activated by ADP, Ca²⁺"],
["α-KG dehydrogenase", "α-KG → Succinyl-CoA + CO₂", "Same cofactors as PDH (B1, B2, B3, B5, lipoic acid)"],
["Succinyl-CoA synthetase", "Succinyl-CoA → Succinate", "Substrate-level phosphorylation → GTP"],
["Succinate dehydrogenase", "Succinate → Fumarate + FADH₂", "Complex II of ETC; inhibited by malonate (competitive inhibitor)"],
]
story.append(two_col_table(
["Key Enzyme", "Reaction", "Regulation / Note"],
rows_tca, s, [2.2*inch, 2.5*inch, 2.3*inch]
))
story.append(sp(1))
story.append(pearl_box(
"TCA cycle intermediates as biosynthetic precursors: Citrate → cytosol → fatty acid synthesis; "
"α-KG → glutamate; Succinyl-CoA → heme synthesis; OAA → aspartate, gluconeogenesis.",
s
))
story.append(sp(2))
# PPP
story.append(Paragraph("Pentose Phosphate Pathway (PPP) — Cytosol", s['topic_header']))
story.append(info_box(
"<b>Substrate:</b> Glucose-6-phosphate. <b>Products (oxidative phase):</b> NADPH + Ribose-5-phosphate + CO₂. "
"Rate-limiting enzyme: <b>G6PD</b> (inhibited by NADPH). "
"Non-oxidative phase uses transketolase (requires Thiamine/B1).",
s
))
story.append(Paragraph("Why NADPH Is Essential:", s['sub_header']))
rows_nadph = [
["Glutathione recycling (GSSG → GSH)", "Antioxidant defense in ALL cells, especially RBCs"],
["Fatty acid synthesis", "2 NADPH per 2-carbon addition by FAS"],
["Cholesterol synthesis", "Multiple steps of HMG-CoA pathway"],
["Cytochrome P450 reactions", "Drug/steroid metabolism in liver"],
["NADPH oxidase (neutrophils)", "O₂ → O₂•⁻ (superoxide) to kill bacteria — INTENTIONAL ROS"],
["Nitric oxide synthase (NOS)", "Arginine → NO (vasodilation, immune defense)"],
]
story.append(two_col_table(["NADPH Use", "Purpose"], rows_nadph, s, [3.2*inch, 3.8*inch]))
story.append(sp(1))
story.append(warning_box(
"G6PD Deficiency (X-linked): Cannot make NADPH → cannot recycle glutathione → oxidative stress → "
"Heinz bodies (denatured Hb) + bite cells → hemolytic anemia. "
"Triggered by: primaquine, dapsone, sulfonamides, fava beans, infection. "
"Most common enzymopathy worldwide. Protective against malaria.",
s
))
story.append(sp(2))
# Malate-Aspartate Shuttle
story.append(Paragraph("Malate-Aspartate Shuttle vs. Glycerol-3-Phosphate Shuttle", s['topic_header']))
story.append(info_box(
"Problem: Glycolysis produces NADH in the CYTOSOL, but NADH cannot cross the inner mitochondrial membrane. "
"Two shuttles transfer the electrons into the mitochondria.",
s
))
rows_shuttle = [
["Malate-Aspartate", "Heart, Liver, Kidney\n('MALI')", "2.5 ATP per cytosolic NADH",
"Cytosolic NADH → malate → crosses membrane → matrix NADH → enters at Complex I",
"More efficient; uses aspartate-glutamate exchanger + malate-α-KG exchanger"],
["Glycerol-3-Phosphate", "Brain, Skeletal Muscle", "1.5 ATP per cytosolic NADH",
"Cytosolic NADH → G3P → crosses membrane → FADH₂ → enters at Complex II",
"Less efficient; FAD-linked (not NAD-linked)"],
]
story.append(two_col_table(
["Shuttle", "Location", "ATP Yield", "Mechanism", "Key Point"],
rows_shuttle, s, [1.3*inch, 1.2*inch, 1.0*inch, 2.0*inch, 1.5*inch]
))
story.append(sp(1))
story.append(mnemonic_box('"MALI organs use MAlate-aspartate and get More ATP (2.5). Brain and muscle use G3P and get less (1.5)."', s))
story.append(sp(1))
story.append(pearl_box(
"Total ATP from 1 glucose (aerobic, with malate-aspartate shuttle): "
"2 (glycolysis substrate-level) + 5 (2 cytosolic NADH via M-A shuttle) + 5 (2 PDH NADH) + "
"15 (6 TCA NADH) + 3 (2 TCA FADH₂) + 2 (2 GTP) = <b>~30–32 ATP total</b>.",
s
))
story.append(sp(3))
return story
def build_ros(styles):
s = styles
story = []
story.append(section_banner("TOPIC 5: ROS NEUTRALIZATION", CORAL, s))
story.append(sp(2))
story.append(Paragraph("Reactive Oxygen Species (ROS)", s['topic_header']))
rows = [
["Superoxide (O₂•⁻)", "ETC leakage, NADPH oxidase", "Converted by SOD to H₂O₂"],
["Hydrogen peroxide (H₂O₂)", "SOD reaction, peroxisomal oxidases", "Converted by catalase or GPx to H₂O"],
["Hydroxyl radical (•OH)", "H₂O₂ + Fe²⁺ (Fenton reaction)", "MOST DANGEROUS — damages DNA, proteins, lipids; no enzyme neutralizes it directly"],
["Peroxynitrite (ONOO⁻)", "O₂•⁻ + NO•", "Potent oxidant; damages mitochondria"],
]
story.append(two_col_table(["ROS", "Source", "Fate/Note"], rows, s, [1.5*inch, 2.2*inch, 3.3*inch]))
story.append(sp(2))
story.append(Paragraph("Enzymatic Antioxidant Defenses", s['sub_header']))
rows2 = [
["Superoxide dismutase (SOD)", "O₂•⁻ → H₂O₂", "Cu/Zn-SOD (cytosol); Mn-SOD (mitochondria)\nSOD1 (Cu/Zn) mutation → familial ALS"],
["Catalase", "2 H₂O₂ → 2 H₂O + O₂", "In PEROXISOMES; heme-containing; abundant in liver, RBCs"],
["Glutathione peroxidase (GPx)", "H₂O₂ + 2 GSH → 2 H₂O + GSSG", "Requires SELENIUM cofactor; primary H₂O₂ scavenger in RBCs"],
["Glutathione reductase", "GSSG + NADPH → 2 GSH", "Regenerates active GSH; requires NADPH (from PPP/G6PD)"],
]
story.append(two_col_table(["Enzyme", "Reaction", "Key Notes"], rows2, s, [1.8*inch, 2.2*inch, 3.0*inch]))
story.append(sp(2))
story.append(Paragraph("Non-Enzymatic Antioxidants", s['sub_header']))
rows3 = [
["Glutathione (GSH)", "Tripeptide: Glu-Cys-Gly", "Most important intracellular antioxidant"],
["Vitamin E (α-tocopherol)", "Lipid-soluble", "Protects cell membranes from lipid peroxidation; chain-breaking antioxidant"],
["Vitamin C (ascorbate)", "Water-soluble", "Donates electrons to free radicals; regenerates Vitamin E"],
["β-carotene", "Fat-soluble", "Quenches singlet oxygen (¹O₂)"],
]
story.append(two_col_table(["Antioxidant", "Solubility", "Function"], rows3, s, [1.8*inch, 1.5*inch, 3.7*inch]))
story.append(sp(2))
story.append(mnemonic_box('"RBC antioxidant chain: G6PD → NADPH → Glutathione Reductase → GSH → GPx → H₂O₂ neutralized. Break ANY link in this chain = hemolysis."', s))
story.append(sp(2))
story.append(Paragraph("High-Yield Clinical Correlates", s['sub_header']))
story.append(pearl_box(
"Chronic Granulomatous Disease (CGD): NADPH oxidase deficiency → no O₂•⁻ → can't kill "
"catalase-positive organisms (S. aureus, Aspergillus, Nocardia, Serratia). "
"NBT test negative. X-linked or AR. Treat with IFN-γ + prophylactic antibiotics/antifungals.",
s
))
story.append(sp(1))
story.append(pearl_box(
"Acetaminophen (APAP) overdose: CYP2E1 → NAPQI (toxic metabolite) depletes glutathione → hepatocyte necrosis (centrilobular). "
"Treat with N-acetylcysteine (NAC) — replenishes cysteine for GSH synthesis.",
s
))
story.append(sp(1))
story.append(pearl_box(
"Reperfusion injury: ischemia converts xanthine dehydrogenase → xanthine oxidase. "
"On reperfusion, burst of O₂•⁻ and H₂O₂ → tissue damage (myocardial infarction, stroke).",
s
))
story.append(sp(3))
return story
def build_neuroglia(styles):
s = styles
story = []
story.append(section_banner("TOPIC 6: MYELIN & NEUROGLIA", TEAL, s))
story.append(sp(2))
story.append(Paragraph("Glial Cell Comparison Table", s['topic_header']))
rows = [
["Astrocyte", "CNS", "Neuroectoderm", "BBB maintenance (end feet), K⁺ buffering, glutamate reuptake, glycogen storage, reactive gliosis",
"GFAP+; Alzheimer type II astrocytes (hepatic encephalopathy); GBM"],
["Oligodendrocyte", "CNS", "Neuroectoderm", "Myelinates up to 50 axons; one cell = multiple internodes",
"Destroyed in MS; no Schwann-like ability to regenerate"],
["Schwann cell", "PNS", "Neural crest", "One cell = ONE internode of ONE axon; also envelops unmyelinated axons (Remak bundles)",
"Schwannoma (NF2: bilateral acoustic); GBS (immune attack)"],
["Microglia", "CNS", "Yolk sac myeloid precursors (NOT neural crest!)", "CNS macrophages; phagocytosis; antigen presentation; cytokine release",
"Activated in MS, Alzheimer, Parkinson, HIV dementia; form microglial nodules"],
["Ependymal cells", "CNS", "Neuroectoderm", "Line ventricles; produce/circulate CSF; have cilia",
"Ependymoma (4th ventricle in children)"],
]
story.append(two_col_table(
["Cell Type", "Location", "Origin", "Key Functions", "Clinical"],
rows, s, [1.1*inch, 0.6*inch, 1.3*inch, 2.2*inch, 1.8*inch]
))
story.append(sp(2))
story.append(warning_box(
"USMLE TRAP: Microglia are NOT derived from neural crest or neuroectoderm. "
"They come from YOLK SAC myeloid precursors (same lineage as macrophages). "
"They infiltrate the CNS early in development.",
s
))
story.append(sp(2))
story.append(Paragraph("Myelin Structure & Function", s['sub_header']))
story.append(info_box(
"<b>Composition:</b> 70% lipid, 30% protein. "
"<b>CNS myelin proteins:</b> PLP (most abundant CNS myelin protein), MBP, MAG. "
"<b>PNS myelin proteins:</b> P0 (most abundant PNS myelin protein), MBP, MAG. "
"<b>Nodes of Ranvier:</b> gaps between myelin sheaths; Na⁺ channels concentrated here; "
"action potentials 'jump' between nodes = saltatory conduction (up to 120 m/s).",
s
))
story.append(sp(2))
story.append(Paragraph("Demyelinating Disease Comparison", s['sub_header']))
rows_dm = [
["Multiple Sclerosis (MS)", "Oligodendrocytes (CNS)", "Periventricular, optic nerve, corpus callosum",
"Oligoclonal bands, ↑IgG in CSF", "Relapsing-remitting; DTRs preserved early"],
["Guillain-Barré (GBS)", "Schwann cells (PNS)", "Peripheral nerves, ascending",
"Albuminocytologic dissociation (↑protein, normal WBC)", "Areflexia; post-infection (C. jejuni, CMV, EBV)"],
["Charcot-Marie-Tooth", "Schwann cells (PNS)", "Peripheral nerves",
"Genetic testing (PMP22, MPZ, GJB1)", "Hereditary; foot deformity (pes cavus), weakness"],
]
story.append(two_col_table(
["Disease", "Cell Targeted", "Location", "CSF / Lab", "Key Feature"],
rows_dm, s, [1.3*inch, 1.4*inch, 1.4*inch, 1.6*inch, 1.3*inch]
))
story.append(sp(3))
return story
def build_axonal_transport(styles):
s = styles
story = []
story.append(section_banner("TOPIC 7: AXONAL TRANSPORT", NAVY, s))
story.append(sp(2))
story.append(Paragraph("Overview", s['topic_header']))
story.append(info_box(
"Axons have virtually no ribosomes → most proteins synthesized in soma and transported down axon. "
"Cutting axon from cell body → <b>Wallerian degeneration</b> of distal segment. "
"Transport occurs along <b>microtubule tracks</b> powered by molecular motors.",
s
))
story.append(sp(2))
rows = [
["Anterograde\n(Fast)", "Soma → Terminal", "~200–400 mm/day", "<b>Kinesin</b> (plus-end directed)\nATP-dependent",
"Synaptic vesicle precursors, mitochondria, membrane proteins, smooth ER"],
["Anterograde\n(Slow)", "Soma → Terminal", "0.5–10 mm/day", "Kinesin (slow component)\nATP-dependent",
"Cytoskeletal proteins (tubulin, actin, neurofilaments), metabolic enzymes"],
["Retrograde", "Terminal → Soma", "~200 mm/day", "<b>Dynein</b> (minus-end directed)\nATP-dependent",
"Used vesicle membranes for recycling, endosomes, NGF, trophic signals, VIRUSES & TOXINS"],
]
story.append(two_col_table(
["Type", "Direction", "Speed", "Motor / Energy", "Cargo"],
rows, s, [0.85*inch, 1.0*inch, 1.0*inch, 1.6*inch, 2.55*inch]
))
story.append(sp(2))
story.append(mnemonic_box('"Kinesin = Kometo (goes away from cell body toward terminal). Dynein = Dynein drags stuff back to Dorm (cell body)."', s))
story.append(sp(2))
story.append(Paragraph("Retrograde Hijackers (HIGH YIELD)", s['sub_header']))
rows2 = [
["Rabies virus", "Peripheral nerve → dorsal root ganglion → CNS", "Furious or paralytic rabies; encephalitis"],
["Herpes simplex (HSV)", "Sensory nerve endings → dorsal root ganglion (latency)", "Cold sores, genital herpes; reactivates under stress"],
["Poliovirus", "NMJ → motor neuron soma", "Destruction of anterior horn cells → flaccid paralysis"],
["Tetanus toxin", "NMJ → spinal cord inhibitory interneurons", "Blocks glycine/GABA → spastic paralysis, trismus (lockjaw)"],
["NGF (nerve growth factor)", "Target organ → sympathetic/sensory neuron soma", "Trophic signal for neuron survival"],
]
story.append(two_col_table(
["Agent", "Route", "Disease / Effect"],
rows2, s, [1.5*inch, 3.0*inch, 2.5*inch]
))
story.append(sp(2))
story.append(warning_box(
"Botulinum toxin does NOT travel retrograde. It acts at the NMJ presynaptic terminal, "
"cleaves SNARE proteins → blocks ACh release → FLACCID paralysis. "
"Tetanus travels retrograde → SPASTIC paralysis. Know the difference!",
s
))
story.append(sp(3))
return story
def build_synapses(styles):
s = styles
story = []
story.append(section_banner("TOPIC 8: SYNAPSES & NEUROTRANSMITTERS", TEAL, s))
story.append(sp(2))
story.append(Paragraph("Synaptic Transmission — Step by Step", s['topic_header']))
steps = [
"Action potential reaches presynaptic terminal",
"Voltage-gated Ca²⁺ channels open (N-type/P-Q type) → Ca²⁺ influx",
"Ca²⁺ binds synaptotagmin (Ca²⁺ sensor) → triggers SNARE complex zippering",
"v-SNARE (synaptobrevin/VAMP) on vesicle + t-SNAREs (syntaxin + SNAP-25) on membrane → fusion → exocytosis",
"Neurotransmitter diffuses across 20–40 nm synaptic cleft",
"NT binds postsynaptic receptors (ionotropic = fast ms; metabotropic/GPCR = slow s–min)",
"Signal termination: reuptake (DA, 5-HT, NE, GABA), enzymatic degradation (ACh by AChE), or diffusion",
]
for i, step in enumerate(steps, 1):
story.append(Paragraph(f"{i}. {step}", s['bullet']))
story.append(sp(2))
story.append(pearl_box(
"SNARE proteins: Botulinum toxin cleaves synaptobrevin (and SNAP-25 for types A,E) → "
"blocks ACh at NMJ → FLACCID paralysis. "
"Tetanus toxin cleaves synaptobrevin in INHIBITORY interneurons → blocks glycine/GABA → SPASTIC paralysis.",
s
))
story.append(sp(2))
story.append(Paragraph("Neurotransmitter Summary Table", s['topic_header']))
rows = [
["ACh", "Choline + Acetyl-CoA", "Choline acetyltransferase", "NMJ, ANS ganglia, basal forebrain",
"nAChR (ion), mAChR (GPCR)", "AChE in cleft; choline reuptake"],
["Dopamine (DA)", "Tyrosine → DOPA → DA", "Tyrosine hydroxylase ★", "Substantia nigra, VTA",
"D1–D5 (all GPCR)", "DAT reuptake; MAO-B, COMT"],
["Norepinephrine (NE)", "DA → NE", "Dopamine-β-hydroxylase", "Locus coeruleus, sympathetic ganglia",
"α1, α2, β1, β2 (GPCR)", "NET reuptake; MAO-A, COMT"],
["Serotonin (5-HT)", "Tryptophan → 5-HTP → 5-HT", "Tryptophan hydroxylase ★", "Raphe nuclei",
"5-HT₃ (ion); all others GPCR", "SERT reuptake; MAO-A"],
["Glutamate", "α-KG (TCA)", "Glutaminase", "Most excitatory CNS synapses",
"NMDA, AMPA, kainate (ion); mGluR (GPCR)", "EAAT transporters (astrocytes)"],
["GABA", "Glutamate", "GAD (needs Vit B6)", "Most inhibitory CNS synapses",
"GABA-A (Cl⁻ ion); GABA-B (GPCR)", "GAT reuptake transporters"],
["Glycine", "Serine", "SHMT", "Spinal cord inhibitory interneurons",
"GlyR (Cl⁻ ion)", "GlyT reuptake"],
]
story.append(two_col_table(
["NT", "Precursor", "Rate-Limiting Enzyme", "Location", "Receptor", "Inactivation"],
rows, s, [0.7*inch, 1.1*inch, 1.3*inch, 1.2*inch, 1.3*inch, 1.4*inch]
))
story.append(sp(2))
story.append(Paragraph("NMDA Receptor — Coincidence Detector (CRITICAL)", s['sub_header']))
story.append(info_box(
"<b>Requires simultaneously:</b> (1) Glutamate binding + (2) Membrane depolarization to remove Mg²⁺ block + (3) Glycine co-agonist. "
"When both conditions met → Ca²⁺ influx → CaM kinase II activation → LTP (learning and memory). "
"<b>Blocked by:</b> Ketamine (anesthesia), Memantine (Alzheimer's), PCP (psychosis model), Mg²⁺ (at rest), Ethanol.",
s
))
story.append(sp(2))
story.append(Paragraph("Dopamine Pathways (HIGH YIELD for Schizophrenia)", s['sub_header']))
rows_da = [
["Mesolimbic", "VTA → limbic system", "Reward, motivation", "↑ in schizophrenia (positive symptoms)", "D2 antagonists (antipsychotics) target here"],
["Mesocortical", "VTA → prefrontal cortex", "Cognition, emotion", "↓ in schizophrenia (negative symptoms)", "Blocking here worsens negative symptoms"],
["Nigrostriatal", "Substantia nigra → striatum", "Motor control, movement", "↓ in Parkinson's disease", "L-DOPA + carbidopa replaces DA"],
["Tuberoinfundibular", "Hypothalamus → anterior pituitary", "Inhibits prolactin release", "Antipsychotics block D2 here", "→ hyperprolactinemia → gynecomastia, galactorrhea, amenorrhea"],
]
story.append(two_col_table(
["Pathway", "Route", "Function", "Disease Relevance", "Drug Effect"],
rows_da, s, [1.1*inch, 1.3*inch, 1.2*inch, 1.5*inch, 1.9*inch]
))
story.append(sp(3))
return story
def build_gpcr(styles):
s = styles
story = []
story.append(section_banner("TOPIC 9: GPCR SIGNALING", NAVY, s))
story.append(sp(2))
story.append(Paragraph("GPCR Structure", s['topic_header']))
story.append(info_box(
"<b>7 transmembrane (7-TM) alpha-helical domains</b>. N-terminus: extracellular (glycosylated, ligand binding). "
"C-terminus: intracellular (phosphorylation site for GRK). "
"3rd intracellular loop (ICL3): couples to G-protein. "
"Associated heterotrimeric G-protein (Gα-GDP + Gβγ) at intracellular face. "
">800 GPCRs in human genome — largest receptor superfamily.",
s
))
story.append(sp(2))
story.append(Paragraph("G-Protein Types — MEMORIZE", s['topic_header']))
rows_g = [
["Gs (stimulatory)", "Adenylyl cyclase ↑", "cAMP ↑ → PKA ↑",
"β1, β2 adrenergic; D1, D5; H2 histamine; V2 vasopressin; glucagon; PTH; TSH; ACTH",
"Cholera toxin ADP-ribosylates Gαs → permanent activation → massive cAMP → secretory diarrhea"],
["Gi (inhibitory)", "Adenylyl cyclase ↓", "cAMP ↓ → PKA ↓",
"α2 adrenergic; M2, M4; D2, D3, D4; μ/δ/κ opioid; GABA-B; adenosine A1",
"Pertussis toxin ADP-ribosylates Gαi → permanent inactivation → cAMP stays high"],
["Gq", "PLC-β ↑", "IP3 ↑ (→ Ca²⁺ release from ER) + DAG ↑ (→ PKC)",
"α1 adrenergic; M1, M3, M5; H1 histamine; AT1 angiotensin; V1 vasopressin; TRH; oxytocin",
"Phorbol esters mimic DAG → constitutive PKC activation → tumor promotion"],
["G12/13", "Rho GEFs", "RhoA activation → cytoskeletal changes",
"Thrombin, LPA, many receptors",
"Stress fiber formation; smooth muscle contraction; platelet shape change"],
]
story.append(two_col_table(
["G-Protein", "Effector", "2nd Messenger / Effect", "Receptors", "Clinical Pearl"],
rows_g, s, [0.8*inch, 1.0*inch, 1.3*inch, 1.8*inch, 2.1*inch]
))
story.append(sp(2))
story.append(mnemonic_box('"s=Stimulate cAMP; i=Inhibit cAMP; q=sQueeze PLC (triggers IP3+DAG); 12/13=Rho (cytoskeleton)"', s))
story.append(sp(2))
story.append(Paragraph("cAMP/PKA Pathway (Gs)", s['sub_header']))
story.append(info_box(
"Gs → adenylyl cyclase → ATP → <b>cAMP</b> → activates <b>PKA</b>. "
"PKA targets: glycogen phosphorylase kinase (↑), glycogen synthase (↓), CREB (gene expression), "
"hormone-sensitive lipase (↑ lipolysis in adipocytes). "
"cAMP degraded by <b>phosphodiesterase (PDE)</b>. "
"PDE inhibitors (sildenafil, theophylline, milrinone, caffeine) → ↑ cAMP/cGMP.",
s
))
story.append(sp(2))
story.append(Paragraph("GRK (G Protein-Coupled Receptor Kinases) & Desensitization", s['topic_header']))
story.append(info_box(
"After prolonged agonist exposure, the cell DESENSITIZES to prevent over-stimulation.",
s
))
steps = [
"Agonist-occupied GPCR is phosphorylated on Ser/Thr (C-tail or ICL3) by <b>GRK</b> (7 isoforms: GRK1–7)",
"Phosphorylated receptor gains high affinity for <b>β-arrestin</b>",
"β-arrestin binds → sterically blocks G-protein coupling → <b>desensitization</b>",
"β-arrestin recruits clathrin + AP-2 → receptor internalized via clathrin-coated pits → <b>downregulation</b>",
"Internalized receptor: recycled back (resensitization) OR sorted to lysosome (degradation)",
]
for i, step in enumerate(steps, 1):
story.append(Paragraph(f"{i}. {step}", s['bullet']))
story.append(sp(1))
story.append(pearl_box(
"GRK isoforms: GRK1 (rhodopsin kinase — mutation → Oguchi disease / stationary night blindness). "
"GRK2 (β-ARK1) — upregulated in heart failure → β-receptor desensitization worsens cardiac function (therapeutic target). "
"β-arrestin also signals independently ('biased agonism') — activates ERK1/2 after receptor internalization.",
s
))
story.append(sp(2))
story.append(Paragraph("MAP Kinase (RAS-ERK) Pathway", s['topic_header']))
story.append(info_box(
"Activated by RTKs (EGF-R, insulin-R, PDGF-R) and GPCRs (via Gβγ or β-arrestin).",
s
))
cascade = [
"Ligand → RTK dimerizes → Tyr autophosphorylation",
"<b>Grb2</b> (SH2 domain) binds phosphoTyr → recruits <b>SOS</b> (RAS-GEF via SH3 domain)",
"<b>SOS activates RAS</b>: GDP → GTP exchange on RAS protein",
"<b>RAS-GTP → activates RAF</b> (MAP3K; first kinase in cascade)",
"<b>RAF phosphorylates MEK</b> (MAP2K = MKK1/2) → MEK activated",
"<b>MEK phosphorylates ERK1/2</b> (MAPK = extracellular signal-regulated kinase)",
"<b>ERK1/2</b> → nucleus → phosphorylates Elk-1, c-Fos, c-Myc → gene expression → proliferation, differentiation, survival",
]
for i, step in enumerate(cascade, 1):
story.append(Paragraph(f"{i}. {step}", s['bullet']))
story.append(sp(1))
story.append(mnemonic_box('"RAS-RAF-MEK-ERK: Remember At Medical Exam Results" or "Grb2-SOS-RAS-RAF-MEK-ERK"', s))
story.append(sp(2))
story.append(Paragraph("MAPK Pathway Cancer Mutations (MUST KNOW)", s['sub_header']))
rows_mut = [
["KRAS G12V/G12D", "Locks RAS in GTP-active state (GAP cannot work)", "Pancreatic cancer >90%, colorectal, lung adenocarcinoma", "KRAS mutations = NO response to anti-EGFR therapy (cetuximab)"],
["BRAF V600E", "Constitutively active RAF kinase", "Melanoma >50%, papillary thyroid, hairy cell leukemia", "Vemurafenib (BRAF inhibitor); combined with MEK inhibitor (trametinib)"],
["NF1 deletion", "Loss of RAS-GAP (neurofibromin) → RAS stays active", "Neurofibromatosis type 1; optic glioma, NF-associated tumors", "NF1: café-au-lait spots, Lisch nodules, neurofibromas"],
["EGFR mutation (exon 19/21)", "Constitutive RTK activity", "Lung adenocarcinoma (non-smokers, Asian women)", "Erlotinib, gefitinib, osimertinib (EGFR TKIs); ONLY if KRAS wild-type"],
]
story.append(two_col_table(
["Mutation", "Mechanism", "Cancer", "Clinical Relevance"],
rows_mut, s, [1.5*inch, 1.7*inch, 1.8*inch, 2.0*inch]
))
story.append(sp(3))
return story
def build_receptors_overview(styles):
s = styles
story = []
story.append(section_banner("TOPIC 10: RECEPTOR TYPES — OVERVIEW", TEAL, s))
story.append(sp(2))
rows = [
["Ion Channel\n(Ionotropic)", "Milliseconds", "NONE needed", "Direct ion flow through pore",
"nAChR (Na⁺/K⁺), GABA-A (Cl⁻), NMDA (Ca²⁺/Na⁺), AMPA (Na⁺/K⁺), glycine-R (Cl⁻)"],
["GPCR\n(Metabotropic)", "Seconds–minutes", "G-proteins, 2nd messengers", "cAMP, IP3/DAG, RhoA",
"Muscarinic (M1–5), Adrenergic (α1,α2,β1,β2), Dopamine (D1–5), opioid, GABA-B"],
["Receptor Tyrosine\nKinase (RTK)", "Minutes–hours", "RAS, PI3K", "Phosphorylation cascade",
"Insulin-R, EGF-R, PDGF-R, VEGF-R, FGF-R, IGF-1R"],
["Intracellular / Nuclear\nReceptor", "Hours–days", "None (ligand enters cell)", "Direct gene transcription (HREs)",
"Glucocorticoid-R, mineralocorticoid-R, androgen-R, ER, PR, thyroid-R (T3), Vit D-R, RA-R"],
]
story.append(two_col_table(
["Receptor Class", "Speed", "Transducer", "Mechanism", "Examples"],
rows, s, [1.1*inch, 0.9*inch, 1.1*inch, 1.2*inch, 2.7*inch]
))
story.append(sp(2))
story.append(pearl_box(
"RTK vs. GPCR: Both activate MAPK/ERK. RTKs directly phosphorylate Tyr. "
"GPCRs go via Gβγ → Grb2 → SOS → RAS, or via β-arrestin after desensitization.",
s
))
story.append(sp(2))
story.append(pearl_box(
"Nuclear receptors: When UNBOUND, many are held in cytoplasm by HSP90 (heat shock protein 90). "
"Ligand binding displaces HSP90 → receptor translocates to nucleus → binds HRE → transcription. "
"Exception: Thyroid hormone receptor is ALWAYS in nucleus (even unbound — acts as repressor).",
s
))
story.append(sp(3))
return story
def build_quick_ref(styles):
s = styles
story = []
story.append(section_banner("QUICK REFERENCE: HIGH-YIELD FACTS & MNEMONICS", AMBER, s))
story.append(sp(2))
story.append(Paragraph("Master Mnemonics", s['topic_header']))
mnemonics = [
("GLUTs", "1=All cells/brain (always on), 2=Liver/sensor, 3=Neurons (highest affinity), 4=Muscle (Insulin-dependent), 5=Fructose only"),
("PDH cofactors", "The Fairy Needs Candy Licorice = Thiamine (B1), FAD (B2), NAD (B3), CoA (B5), Lipoic acid"),
("Malate-aspartate shuttle organs", "MALI = Heart (M), Liver (A), Kidney (L+I) → More ATP (2.5 per NADH)"),
("G-proteins", "s=Stimulate cAMP, i=Inhibit cAMP, q=sQueeze PLC → IP3+DAG, 12/13=Rho cytoskeleton"),
("RAS-MAPK cascade", "Grb2-SOS-RAS-RAF-MEK-ERK (anagram: Go Slam Racing Fast Many Excellent times)"),
("Axonal motors", "Kinesin goes to synaptic terminal (anterograde); Dynein goes back to soma (retrograde)"),
("RBC antioxidant chain", "G6PD → NADPH → GSH (via GR) → GPx → H₂O₂ neutralized; break = hemolysis"),
("Dopamine pathways", "MNLT: Mesolimbic (reward), Mesocortical (cognition), Nigrostriatal (motor), Tuberoinfundibular (prolactin)"),
("Glial cell origins", "Micro = Yolk sac (macrophage lineage), Oligo/Astro/Ependymal = Neuroectoderm, Schwann = Neural crest"),
]
for label, text in mnemonics:
story.append(mnemonic_box(f"[{label}] {text}", s))
story.append(sp(1))
story.append(sp(2))
story.append(Paragraph("Top USMLE Traps", s['topic_header']))
traps = [
"GLUT2 (not GLUT4) is the glucose SENSOR in beta cells — NOT insulin-regulated",
"Giving IV glucose to a thiamine-deficient patient FIRST worsens Wernicke's — always give B1 first",
"Cholera toxin locks Gαs ON (not Gs receptor ON); pertussis locks Gαi OFF",
"Botulinum = FLACCID paralysis (blocks ACh release at NMJ); Tetanus = SPASTIC (blocks inhibitory NT at spinal cord)",
"Phosphatidylserine on OUTER leaflet = apoptosis signal AND coagulation trigger",
"Microglia derive from yolk sac myeloid precursors — NOT neural crest, NOT neuroectoderm",
"One oligodendrocyte myelinates MANY axons (up to 50); one Schwann cell myelinates ONE axon segment",
"RAS mutations prevent GTP hydrolysis (GAP cannot work) → constitutively active → KRAS = most common oncogene mutation",
"BRAF V600E in melanoma → vemurafenib; but add MEK inhibitor (trametinib) to prevent resistance",
"EGFR inhibitors (erlotinib) only work if KRAS is wild-type — KRAS mutation = no response",
"G6PD deficiency: Heinz bodies (Hb denatured inside RBC) + bite cells (macrophages bite Heinz bodies out)",
"Pyruvate kinase deficiency → hemolytic anemia (RBCs rely only on glycolysis for ATP)",
"NMDA receptor: needs BOTH glutamate AND depolarization (to remove Mg²⁺) AND glycine co-agonist",
"Tyrosine hydroxylase is rate-limiting for dopamine AND norepinephrine AND epinephrine synthesis",
"Tryptophan hydroxylase is rate-limiting for serotonin synthesis",
"Succinate dehydrogenase = Complex II of ETC; only TCA enzyme embedded in inner mitochondrial membrane (not in matrix)",
]
for trap in traps:
story.append(warning_box(trap, s))
story.append(sp(1))
story.append(sp(3))
return story
# ── Main build ─────────────────────────────────────────────────────────────────
def build_pdf():
styles = build_styles()
doc = BaseDocTemplate(
OUTPUT_PATH,
pagesize=letter,
leftMargin=0.75*inch,
rightMargin=0.75*inch,
topMargin=0.85*inch,
bottomMargin=0.75*inch,
title="USMLE High-Yield Study Guide",
author="Orris AI",
subject="Cell Biology, Biochemistry, Neuroscience"
)
cover_frame = Frame(0, 0, letter[0], letter[1], id='cover')
normal_frame = Frame(
0.75*inch, 0.75*inch,
letter[0] - 1.5*inch, letter[1] - 1.5*inch,
id='normal'
)
doc.addPageTemplates([
PageTemplate(id='Cover', frames=[cover_frame], onPage=on_cover),
PageTemplate(id='Normal', frames=[normal_frame], onPage=on_page),
])
story = []
# Cover page
story += build_cover(styles)
# Switch to normal template
from reportlab.platypus import NextPageTemplate
story.append(NextPageTemplate('Normal'))
story.append(PageBreak())
story += build_plasma_membrane(styles)
story.append(PageBreak())
story += build_transporters(styles)
story.append(PageBreak())
story += build_gluts(styles)
story.append(PageBreak())
story += build_carb_metabolism(styles)
story.append(PageBreak())
story += build_ros(styles)
story.append(PageBreak())
story += build_neuroglia(styles)
story.append(PageBreak())
story += build_axonal_transport(styles)
story.append(PageBreak())
story += build_synapses(styles)
story.append(PageBreak())
story += build_gpcr(styles)
story.append(PageBreak())
story += build_receptors_overview(styles)
story.append(PageBreak())
story += build_quick_ref(styles)
doc.build(story)
print(f"PDF built successfully: {OUTPUT_PATH}")
if __name__ == '__main__':
build_pdf()