Awake craniotomy in details
"awake craniotomy" technique outcomes
Awake craniotomy in details anaesthesia implications with more elaborate way
"awake craniotomy" anesthesia technique
"A motivated patient is critical to the success of the procedure. Preoperative assessment should include a detailed explanation of the anesthetic so as to ensure cooperation and allay anxiety." - Barash Clinical Anesthesia 9e
"Awake craniotomy can be performed with the patient sedated for the duration of the procedure, or with an 'asleep-awake-asleep' technique employing a supraglottic airway device." - Barash 9e
"The essential element of an anesthetic for an awake craniotomy is the local anesthetic technique. Sedation cannot compensate for inadequate anesthesia of the scalp." - Miller's Anesthesia 10e

| Nerve | Territory |
|---|---|
| Supratrochlear | Medial forehead |
| Supraorbital | Lateral forehead, anterior scalp |
| Zygomaticotemporal | Temple |
| Auriculotemporal | Temporal region, pre-auricular |
| Lesser occipital | Posterior scalp, lateral |
| Greater occipital | Posterior scalp, medial |
"The volume of local anesthetic used to infiltrate pin sites and perform the scalp nerve blocks can be substantial. It is appropriate for the anesthesiologist to keep track of, and provide advice about, the doses of local anesthetics used." - Miller's Anesthesia 10e
"Dexmedetomidine is the agent of choice for sedation of patients undergoing awake craniotomies." - Morgan & Mikhail Clinical Anesthesiology 7e
| Complication | Cause | Management |
|---|---|---|
| Intraoperative seizure | Cortical stimulation, tumor, or spontaneous | Cold saline irrigation of cortex by surgeon (first line); propofol 0.5-1.0 mg/kg IV (hold briefly to allow spontaneous termination); have phenytoin/levetiracetam ready |
| Respiratory depression / apnea | Oversedation, opioid effect, propofol-remifentanil synergy | Reduce/stop infusions; airway repositioning; jaw thrust; emergency LMA/intubation (very difficult in pin fixation - plan ahead) |
| Airway obstruction | Sedation-induced, positional | Airway repositioning maneuvers; consider nasal airway prior to draping |
| Patient non-cooperation / disinhibition | Anxiety, confusion, paradoxical reaction | Reassurance; small propofol bolus; abort awake phase if needed |
| Oversedation | Excessive drug titration | Hold all infusions; stimulation to arouse; airway rescue |
| Intractable brain swelling | Hypercapnia, venous obstruction, tumor edema | Hyperventilate; mannitol/hypertonic saline; dexamethasone; abort awake phase |
| Pain / discomfort | Inadequate local anesthesia, dural traction | Surgeon supplemental LA infiltration; small opioid bolus; adjust position |
| Nausea and vomiting | Opioids, brain manipulation | Anti-emetics (ondansetron, dexamethasone preop); limit opioids |
| LAST (Local anesthetic systemic toxicity) | Excessive LA volume | Track cumulative doses; have Intralipid 20% immediately available; ACLS |
"Seizures should be treated with cold saline applied to the brain surface by the surgeon and a small bolus of propofol (20 mg) intravenously." - Barash 9e
| Monitor | Purpose |
|---|---|
| Arterial line | Beat-to-beat BP, blood gas sampling |
| SpO2 | Continuous oxygenation |
| Capnography (ETCO2) | Essential - airway patency and ventilation confirmation |
| EEG / ECoG | Seizure localization (by neurophysiology team) |
| Standard ECG, NIBP | Routine |
| Temperature | Prevent hypothermia |
| Neuropsychological testing | Real-time cortical mapping |
| BIS (optional) | Sedation depth titration |
Create a quick reference PDF for awake craniotomy anesthesia team checklist
ls -la /home/daytona/workspace/ 2>/dev/null && mkdir -p /home/daytona/workspace/awake-craniotomy
~/awake-craniotomy/generate_checklist.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import FrameBreak
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/awake-craniotomy/Awake_Craniotomy_Checklist.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
NAVY = HexColor("#1B2A4A")
TEAL = HexColor("#0D7377")
TEAL_LITE = HexColor("#E0F4F4")
RED = HexColor("#C0392B")
RED_LITE = HexColor("#FDECEA")
AMBER = HexColor("#D4700A")
AMBER_LT = HexColor("#FFF3E0")
GREEN = HexColor("#1A6B3C")
GREEN_LT = HexColor("#E8F5E9")
GREY_LT = HexColor("#F4F6F9")
GREY_MID = HexColor("#BDC3C7")
WHITE = colors.white
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=14*mm,
rightMargin=14*mm,
topMargin=14*mm,
bottomMargin=14*mm,
title="Awake Craniotomy Anesthesia Team Checklist",
author="Orris Medical Reference",
)
W, H = A4
CW = W - 28*mm # content width
styles = getSampleStyleSheet()
def style(name, **kw):
s = ParagraphStyle(name, **kw)
return s
# ── Custom paragraph styles ─────────────────────────────────────────────────
S_TITLE = style("title",
fontName="Helvetica-Bold", fontSize=16, textColor=WHITE,
leading=20, alignment=TA_CENTER, spaceAfter=0)
S_SUBTITLE = style("subtitle",
fontName="Helvetica", fontSize=9, textColor=HexColor("#D0E8F2"),
leading=12, alignment=TA_CENTER, spaceAfter=0)
S_SEC = style("sec",
fontName="Helvetica-Bold", fontSize=9.5, textColor=WHITE,
leading=13, spaceAfter=0, spaceBefore=0)
S_ITEM = style("item",
fontName="Helvetica", fontSize=8.2, textColor=HexColor("#1A1A2E"),
leading=11.5, leftIndent=4, spaceAfter=0)
S_ITEM_BOLD = style("item_bold",
fontName="Helvetica-Bold", fontSize=8.2, textColor=HexColor("#1A1A2E"),
leading=11.5, leftIndent=4, spaceAfter=0)
S_WARN = style("warn",
fontName="Helvetica-Bold", fontSize=8, textColor=RED,
leading=11, leftIndent=4, spaceAfter=0)
S_NOTE = style("note",
fontName="Helvetica-Oblique", fontSize=7.5, textColor=HexColor("#555566"),
leading=10, leftIndent=4, spaceAfter=0)
S_DRUG = style("drug",
fontName="Helvetica", fontSize=8, textColor=HexColor("#1A1A2E"),
leading=11, leftIndent=2, spaceAfter=0)
S_DRUG_H = style("drug_h",
fontName="Helvetica-Bold", fontSize=8, textColor=WHITE,
leading=11, leftIndent=2, spaceAfter=0)
S_FOOTER = style("footer",
fontName="Helvetica-Oblique", fontSize=6.5, textColor=HexColor("#888899"),
leading=9, alignment=TA_CENTER)
# ── Helper builders ──────────────────────────────────────────────────────────
def section_header(text, bg=TEAL):
"""Coloured section header bar."""
data = [[Paragraph(f"▌ {text}", S_SEC)]]
t = Table(data, colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 7),
("RIGHTPADDING", (0,0), (-1,-1), 7),
("LINEBELOW", (0,0), (-1,-1), 0.5, WHITE),
]))
return t
def checkbox_row(items, ncols=2, bg=None):
"""
items: list of (text, style, warn_flag)
Returns a Table with checkbox column.
"""
if bg is None:
bg = WHITE
rows = []
# split into ncols columns
col_items = [items[i::ncols] for i in range(ncols)]
max_rows = max(len(c) for c in col_items)
for r in range(max_rows):
row = []
for c in range(ncols):
if r < len(col_items[c]):
txt, sty, warn = col_items[c][r]
cb = "☐"
row.append(Paragraph(cb, S_ITEM))
row.append(Paragraph(txt, sty))
else:
row.append("")
row.append("")
rows.append(row)
# column widths: checkbox narrow, text fills rest
cb_w = 8*mm
txt_w = (CW - ncols * cb_w) / ncols
col_ws = []
for _ in range(ncols):
col_ws += [cb_w, txt_w]
t = Table(rows, colWidths=col_ws, repeatRows=0)
ts = [
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 3),
("RIGHTPADDING", (0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.3, GREY_MID),
]
t.setStyle(TableStyle(ts))
return t
def info_table(rows_data, col_widths, header_bg=NAVY, row_bg=GREY_LT, alt_bg=WHITE):
"""Generic info table with coloured header."""
header = rows_data[0]
body = rows_data[1:]
hrow = [Paragraph(str(h), S_DRUG_H) for h in header]
brows = []
for i, row in enumerate(body):
bg_c = row_bg if i % 2 == 0 else alt_bg
brows.append([Paragraph(str(c), S_DRUG) for c in row])
all_rows = [hrow] + brows
t = Table(all_rows, colWidths=col_widths)
ts_list = [
("BACKGROUND", (0,0), (-1,0), header_bg),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
("ROWBACKGROUNDS", (0,1), (-1,-1), [row_bg, alt_bg]),
]
t.setStyle(TableStyle(ts_list))
return t
# ── Build story ──────────────────────────────────────────────────────────────
story = []
# ── TITLE BANNER ────────────────────────────────────────────────────────────
title_data = [[
Paragraph("AWAKE CRANIOTOMY", S_TITLE),
Paragraph("ANESTHESIA TEAM QUICK-REFERENCE CHECKLIST", S_SUBTITLE),
]]
title_tbl = Table([[
Paragraph("AWAKE CRANIOTOMY<br/><font size=10>ANESTHESIA TEAM QUICK-REFERENCE CHECKLIST</font>", S_TITLE)
]], colWidths=[CW])
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
("LINEBELOW", (0,0), (-1,-1), 2, TEAL),
]))
story.append(title_tbl)
story.append(Spacer(1, 4*mm))
# ── PHASE INDICATOR ROW ──────────────────────────────────────────────────────
phases = [
("PHASE 1", "ASLEEP / INDUCTION", NAVY),
("PHASE 2", "AWAKE / MAPPING", TEAL),
("PHASE 3", "RE-SLEEP / RESECTION & CLOSURE", HexColor("#34495E")),
]
phase_cells = []
for ph, label, bg in phases:
cell = Paragraph(f"<b>{ph}</b><br/><font size=7>{label}</font>",
style("ph", fontName="Helvetica-Bold", fontSize=9,
textColor=WHITE, leading=12, alignment=TA_CENTER))
phase_cells.append(cell)
phase_tbl = Table([phase_cells], colWidths=[CW/3]*3)
phase_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), NAVY),
("BACKGROUND", (1,0), (1,0), TEAL),
("BACKGROUND", (2,0), (2,0), HexColor("#34495E")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("LINEBETWEEN", (0,0), (-1,-1), 1, WHITE),
]))
story.append(phase_tbl)
story.append(Spacer(1, 4*mm))
# ── TWO-COLUMN LAYOUT USING NESTED TABLES ────────────────────────────────────
# Left column content and right column content assembled as nested tables.
def col_block(header_text, header_bg, items_list, bg=GREY_LT):
"""items_list: list of (text, bold, warn)"""
parts = [section_header(header_text, bg=header_bg)]
rows = []
for txt, bold, warn in items_list:
if warn:
s = S_WARN
elif bold:
s = S_ITEM_BOLD
else:
s = S_ITEM
rows.append(("☐ " + txt if not warn else "⚠ " + txt, s))
tbl_rows = []
for txt, s in rows:
tbl_rows.append([Paragraph(txt, s)])
if tbl_rows:
inner = Table(tbl_rows, colWidths=[CW/2 - 4*mm])
inner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 2.5),
("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 4),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.3, GREY_MID),
]))
parts.append(inner)
return parts
# ─────────────── PREOPERATIVE SECTION ───────────────────────────────────────
story.append(section_header("PRE-OPERATIVE ASSESSMENT (≥24 h Before Surgery)", bg=NAVY))
story.append(Spacer(1, 1*mm))
preop_items = [
("Patient motivation & psychological assessment", True, False),
("Explain ALL phases: duration, discomfort, required tasks", False, False),
("Baseline neuropsychological testing documented", False, False),
("Difficult airway assessment (Mallampati, mouth opening, neck)", True, False),
("Obtain history of seizure aura type and character", False, False),
("Anticonvulsants: reduce or hold if ECoG planned (per neuro)", True, False),
("NO benzodiazepine premedication if EEG localization planned", False, True),
("Identify interpreters if language barrier exists", False, False),
("Coagulation screen, FBC, U&E, group & save", False, False),
("Contraindications excluded: morbid obesity, claustrophobia, uncooperative, severe GORD, movement disorder", False, True),
("Intralipid 20% availability confirmed (LAST prophylaxis)", True, False),
("Consent: awake procedure, possible conversion to GA", True, False),
]
preop_rows = [[Paragraph("☐ " + txt if not warn else "⚠ " + txt,
S_ITEM_BOLD if bold and not warn else (S_WARN if warn else S_ITEM))]
for txt, bold, warn in preop_items]
preop_tbl = Table(preop_rows, colWidths=[CW/2 - 3*mm, CW/2 - 3*mm] if False else [CW])
preop_tbl = Table(
[[Paragraph("☐ " + txt if not w else "⚠ " + txt,
S_ITEM_BOLD if b and not w else (S_WARN if w else S_ITEM))
for txt, b, w in preop_items[i::2]]
for i in range((len(preop_items)+1)//2)],
colWidths=[CW/2 - 2*mm, CW/2 - 2*mm]
)
preop_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_LT),
("TOPPADDING", (0,0), (-1,-1), 2.5),
("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.4, GREY_MID),
]))
story.append(preop_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── EQUIPMENT & DRUGS ──────────────────────────────────────────
story.append(section_header("EQUIPMENT & DRUG PREPARATION (Day of Surgery)", bg=HexColor("#2C3E50")))
story.append(Spacer(1, 1*mm))
equip_left = [
"Arterial line kit + transducer",
"LMA (sizes 3, 4, 5) + lubrication",
"Video laryngoscope + bougie (emergency)",
"Nasopharyngeal airway",
"Sidestream ETCO₂ (nasal cannula capnography)",
"SpO₂, ECG, NIBP, temperature",
"BIS monitor (optional)",
"Warming blanket (forced air)",
"Long IV extension sets (≥1.5 m)",
"Urinary catheter kit",
]
equip_right = [
"Propofol infusion (10 mg/mL syringe)",
"Remifentanil infusion (20–50 mcg/mL)",
"Dexmedetomidine infusion (4 mcg/mL)",
"LA kit: ropivacaine 0.75% + bupivacaine 0.5% + epi",
"Lidocaine 2% (topical / airway)",
"Cold normal saline (500 mL, for seizure irrigation)",
"Propofol 20 mg bolus drawn up + labeled",
"Intralipid 20% 500 mL available in room",
"Ondansetron 4 mg IV drawn up",
"Dexamethasone 8 mg IV drawn up",
]
eq_rows = [[Paragraph("☐ " + l, S_ITEM), Paragraph("☐ " + r, S_ITEM)]
for l, r in zip(equip_left, equip_right)]
eq_tbl = Table(eq_rows, colWidths=[CW/2 - 2*mm, CW/2 - 2*mm])
eq_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), WHITE),
("ROWBACKGROUNDS", (0,0), (-1,-1), [GREY_LT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 2.5),
("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.4, GREY_MID),
("LINEBETWEEN", (0,0), (1,-1), 0.3, GREY_MID),
]))
story.append(eq_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── SCALP NERVE BLOCK ──────────────────────────────────────────
story.append(section_header("SCALP NERVE BLOCK — The Cornerstone of Awake Craniotomy", bg=TEAL))
story.append(Spacer(1, 1*mm))
nerve_data = [
["Nerve", "Landmark / Injection Point", "Territory"],
["Supratrochlear", "Medial orbital rim at corrugator", "Medial forehead"],
["Supraorbital", "Supraorbital notch / foramen", "Lateral forehead, anterior scalp"],
["Zygomaticotemporal", "Lateral orbital rim, temporal fossa", "Temple"],
["Auriculotemporal", "1–1.5 cm anterior to tragus, above zygomatic arch", "Temporal scalp, pre-auricular"],
["Lesser occipital", "Posterior border of SCM, ⅓ from mastoid", "Posterior scalp, lateral"],
["Greater occipital", "Medial to occipital artery, 3 cm lateral to midline", "Posterior scalp, medial"],
]
nerve_tbl = info_table(nerve_data,
col_widths=[38*mm, 68*mm, 52*mm],
header_bg=TEAL, row_bg=TEAL_LITE, alt_bg=WHITE)
story.append(nerve_tbl)
warn_la = Table([[Paragraph(
"⚠ TRACK CUMULATIVE LA DOSE — Scalp block + pin site infiltration + dural infiltration = HIGH TOTAL VOLUME | "
"Ropivacaine 0.75% max ~3 mg/kg | Have Intralipid 20% in room",
style("warnbar", fontName="Helvetica-Bold", fontSize=7.8, textColor=WHITE, leading=11, alignment=TA_LEFT)
)]],
colWidths=[CW])
warn_la.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), RED),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
story.append(Spacer(1, 1.5*mm))
story.append(warn_la)
story.append(Spacer(1, 3*mm))
# ─────────────── SEDATION DRUG REFERENCE ────────────────────────────────────
story.append(section_header("SEDATION AGENT QUICK-REFERENCE", bg=HexColor("#6C3483")))
story.append(Spacer(1, 1*mm))
drug_data = [
["Agent", "Induction / Loading", "Maintenance Infusion", "Key Advantage", "Key Caution"],
["Propofol", "0.5–1 mg/kg titrated", "25–75 mcg/kg/min", "Titratable, rapid offset", "Resp. depression; stop 15 min before EEG"],
["Remifentanil", "—", "0.02–0.05 mcg/kg/min", "Ultra-short acting opioid", "Synergistic resp. depression with propofol"],
["Dexmedetomidine", "0.5–1 mcg/kg over 10 min (optional)", "0.2–0.5 mcg/kg/h", "Analgesia + sedation, minimal resp. depression", "Slow onset/offset; possible bradycardia"],
["Propofol + Remi", "Propofol titrated", "As above", "Deep sedation possible", "HIGH resp. depression risk in pin fixation"],
["Dex + Remi", "Dex load ± remi", "As above", "Best respiratory safety", "Ensure remi rate low"],
]
drug_tbl = info_table(drug_data,
col_widths=[28*mm, 34*mm, 38*mm, 46*mm, 36*mm],
header_bg=HexColor("#6C3483"), row_bg=HexColor("#F5EEF8"), alt_bg=WHITE)
story.append(drug_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── PHASE 1 — ASLEEP ────────────────────────────────────────────
story.append(section_header("PHASE 1 — ASLEEP (Induction → Dural Opening)", bg=NAVY))
story.append(Spacer(1, 1*mm))
p1_left = [
("Complete ALL positioning + padding BEFORE sedation", True, False),
("Arterial line sited and zeroed", True, False),
("Verify clear visual access to patient's face", True, False),
("Verify: emergency airway plan discussed with team", False, True),
("Insert nasopharyngeal airway if needed", False, False),
("Sidestream ETCO₂ nasal cannula in place", True, False),
("Bladder catheter in situ", False, False),
("Warming blanket applied", False, False),
]
p1_right = [
("LMA inserted (asleep phase) — size checked", True, False),
("LMA position confirmed: ETCO₂ trace, chest rise", True, False),
("Sedation infusion running (propofol ± dex ± remi)", False, False),
("Pin site LA infiltration completed (track dose)", True, False),
("Scalp nerve block completed (track dose)", True, False),
("Incision line infiltrated by surgeon (track dose)", False, False),
("Brain relaxation: mannitol / hypertonic saline if ordered", False, False),
("Steroids (dexamethasone) given if ordered", False, False),
]
p1_rows = [[
Paragraph("☐ " + l if not lw else "⚠ " + l, S_ITEM_BOLD if lb and not lw else (S_WARN if lw else S_ITEM)),
Paragraph("☐ " + r if not rw else "⚠ " + r, S_ITEM_BOLD if rb and not rw else (S_WARN if rw else S_ITEM))
] for (l, lb, lw), (r, rb, rw) in zip(p1_left, p1_right)]
p1_tbl = Table(p1_rows, colWidths=[CW/2 - 2*mm, CW/2 - 2*mm])
p1_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_LT),
("ROWBACKGROUNDS", (0,0), (-1,-1), [GREY_LT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 2.5),
("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.4, GREY_MID),
("LINEBETWEEN", (0,0), (1,-1), 0.3, GREY_MID),
]))
story.append(p1_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── PHASE 2 — AWAKE ─────────────────────────────────────────────
story.append(section_header("PHASE 2 — AWAKE (Brain Surface Exposed → Mapping Complete)", bg=TEAL))
story.append(Spacer(1, 1*mm))
p2_left = [
("Discontinue propofol ≥15 min BEFORE EEG recording", False, True),
("Dexmedetomidine: reduce to 0.1–0.3 mcg/kg/h for testing", True, False),
("LMA removed — confirm spontaneous ventilation", True, False),
("Patient oriented and responsive before mapping begins", True, False),
("Nasal O₂ (4 L/min) + ETCO₂ monitoring continuous", True, False),
("Surgical drape: confirm face is fully visible to team", True, False),
("Verbal communication established with patient", True, False),
("Baseline neurological test performed (naming, counting)", False, False),
]
p2_right = [
("Neuropsychologist / speech therapist present and ready", False, False),
("Cold saline 500 mL drawn up and labeled at surgical field", False, True),
("Propofol 20 mg bolus labeled and immediately accessible", False, True),
("Anticonvulsants immediately accessible (phenytoin/LEV)", False, False),
("Monitor ETCO₂: target 35–40 mmHg (avoid hypercapnia)", True, False),
("Reassure patient continuously; explain each stimulus", False, False),
("If oversedated: stop all infusions, stimulate, jaw thrust", False, True),
("Note: brain parenchyma manipulation is PAINLESS", False, False),
]
p2_rows = [[
Paragraph("☐ " + l if not lw else "⚠ " + l, S_ITEM_BOLD if lb and not lw else (S_WARN if lw else S_ITEM)),
Paragraph("☐ " + r if not rw else "⚠ " + r, S_ITEM_BOLD if rb and not rw else (S_WARN if rw else S_ITEM))
] for (l, lb, lw), (r, rb, rw) in zip(p2_left, p2_right)]
p2_tbl = Table(p2_rows, colWidths=[CW/2 - 2*mm, CW/2 - 2*mm])
p2_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL_LITE),
("ROWBACKGROUNDS", (0,0), (-1,-1), [TEAL_LITE, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 2.5),
("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.4, GREY_MID),
("LINEBETWEEN", (0,0), (1,-1), 0.3, GREY_MID),
]))
story.append(p2_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── PHASE 3 — RE-SLEEP ──────────────────────────────────────────
story.append(section_header("PHASE 3 — RE-SLEEP (Resection & Closure)", bg=HexColor("#34495E")))
story.append(Spacer(1, 1*mm))
p3_items = [
("Mapping complete — confirmed with surgeon and neuropsychologist", True, False),
("Re-induce sedation / general anesthesia", True, False),
("Re-insert LMA — confirm position with ETCO₂", True, False),
("Propofol infusion re-started (± remifentanil)", False, False),
("Most patients tolerate sedation (not full GA) for closure", False, False),
("Anti-emetic given if not already (ondansetron 4 mg)", False, False),
("Post-op pain plan: scalp block provides good analgesia", False, False),
("Mannitol / hypertonic saline given if brain swelling", False, False),
]
p3_rows = [[Paragraph("☐ " + txt if not w else "⚠ " + txt,
S_ITEM_BOLD if b and not w else (S_WARN if w else S_ITEM))]
for txt, b, w in p3_items]
p3_rows2 = [[
Paragraph("☐ " + p3_items[i][0] if not p3_items[i][2] else "⚠ " + p3_items[i][0],
S_ITEM_BOLD if p3_items[i][1] and not p3_items[i][2] else (S_WARN if p3_items[i][2] else S_ITEM)),
Paragraph("☐ " + p3_items[i+1][0] if i+1 < len(p3_items) and not p3_items[i+1][2] else
("⚠ " + p3_items[i+1][0] if i+1 < len(p3_items) else ""),
S_ITEM_BOLD if i+1 < len(p3_items) and p3_items[i+1][1] and not p3_items[i+1][2]
else (S_WARN if i+1 < len(p3_items) and p3_items[i+1][2] else S_ITEM))
] for i in range(0, len(p3_items), 2)]
p3_tbl = Table(p3_rows2, colWidths=[CW/2 - 2*mm, CW/2 - 2*mm])
p3_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_LT),
("ROWBACKGROUNDS", (0,0), (-1,-1), [GREY_LT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 2.5),
("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.4, GREY_MID),
("LINEBETWEEN", (0,0), (1,-1), 0.3, GREY_MID),
]))
story.append(p3_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── COMPLICATIONS RESPONSE ──────────────────────────────────────
story.append(section_header("INTRAOPERATIVE COMPLICATION RESPONSE", bg=RED))
story.append(Spacer(1, 1*mm))
comp_data = [
["Complication", "First-Line Response", "Second-Line / Escalation"],
["Intraoperative SEIZURE",
"1. Signal surgeon: cold saline irrigation to cortex\n2. Stop cortical stimulation\n3. Observe 30 s for spontaneous termination",
"Propofol 0.5–1 mg/kg IV bolus (20 mg increments)\nLevetiracetam / phenytoin if refractory\nSecure airway if LOC"],
["Respiratory DEPRESSION / Apnea",
"Stop propofol + remifentanil immediately\nJaw thrust + head-tilt\nNasal airway / O₂ increase",
"LMA insertion (difficult in pin fixation — pre-plan)\nEmergency intubation: video laryngoscope\nCall for additional help"],
["Patient NON-COOPERATION",
"Verbal reassurance\nIdentify cause (pain → more LA; anxiety → small propofol 10–20 mg)",
"Abort awake phase\nConvert to GA (pre-planned route)\nDocument for future cases"],
["BRAIN SWELLING",
"Ensure no hypercapnia (ETCO₂ <40 mmHg)\nHead position optimized, venous drainage unobstructed",
"Mannitol 0.5–1 g/kg or 3% saline 100–150 mL\nDexamethasone\nSurgeon may need to abort resection"],
["LA SYSTEMIC TOXICITY (LAST)",
"Stop LA immediately\nCalls for help\nO₂ 100%, ABCDE",
"Intralipid 20% 1.5 mL/kg bolus → 0.25 mL/kg/min\nAvoid propofol (lipid carrier insufficient)\nCPR if cardiac arrest"],
["Nausea / Vomiting",
"Ondansetron 4 mg IV\nMetoclopramide 10 mg IV\nLimit opioids",
"Dexamethasone 4–8 mg IV\nAspiration precautions\nPosition head-up if possible"],
]
comp_tbl = info_table(comp_data,
col_widths=[36*mm, 72*mm, 70*mm],
header_bg=RED, row_bg=RED_LITE, alt_bg=WHITE)
story.append(comp_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── POST-OP HANDOVER ────────────────────────────────────────────
story.append(section_header("POST-OPERATIVE HANDOVER POINTS", bg=GREEN))
story.append(Spacer(1, 1*mm))
postop_items = [
("Neurological baseline documented intraoperatively (speech, motor, sensory)", True, False),
("Document total LA volumes used (scalp block + pin sites + dural)", True, False),
("Anticonvulsants restarted per neurology instructions", True, False),
("Adequate analgesia prescribed (paracetamol, NSAIDs ± opioids)", False, False),
("New neurological deficit — immediate CT head if suspected", False, True),
("ICU/HDU vs PACU: decision per case complexity", False, False),
("Monitoring: GCS, BP (avoid hypertension), SpO₂, temperature", False, False),
("Inform ward of seizure risk and emergency response", False, False),
]
po_rows2 = [[
Paragraph("☐ " + postop_items[i][0] if not postop_items[i][2] else "⚠ " + postop_items[i][0],
S_ITEM_BOLD if postop_items[i][1] and not postop_items[i][2] else (S_WARN if postop_items[i][2] else S_ITEM)),
Paragraph("☐ " + postop_items[i+1][0] if i+1 < len(postop_items) and not postop_items[i+1][2] else
("⚠ " + postop_items[i+1][0] if i+1 < len(postop_items) else ""),
S_ITEM_BOLD if i+1 < len(postop_items) and postop_items[i+1][1] and not postop_items[i+1][2]
else (S_WARN if i+1 < len(postop_items) and postop_items[i+1][2] else S_ITEM))
] for i in range(0, len(postop_items), 2)]
po_tbl = Table(po_rows2, colWidths=[CW/2 - 2*mm, CW/2 - 2*mm])
po_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREEN_LT),
("ROWBACKGROUNDS", (0,0), (-1,-1), [GREEN_LT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 2.5),
("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,-1), (-1,-1), 0.4, GREY_MID),
("LINEBETWEEN", (0,0), (1,-1), 0.3, GREY_MID),
]))
story.append(po_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── KEY REMINDERS BOX ───────────────────────────────────────────
reminders = [
"Sedation CANNOT replace an inadequate scalp block — fix the block, not the drug dose.",
"ETCO₂ >45 mmHg = cerebral vasodilation → brain swelling → poor surgical field. Act immediately.",
"In pin fixation, EMERGENCY AIRWAY ACCESS IS EXTREMELY LIMITED — plan before you sedate.",
"Propofol must be STOPPED ≥15 min before EEG recording — residual beta activity obscures seizure foci.",
"Language mapping can ONLY be performed in an awake patient — GA surrogate testing is not equivalent.",
]
rem_rows = [[Paragraph(f"★ {r}",
style("rem", fontName="Helvetica-Bold", fontSize=7.8,
textColor=NAVY, leading=11, leftIndent=2))]
for r in reminders]
rem_tbl = Table(rem_rows, colWidths=[CW])
rem_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), AMBER_LT),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,0), (-1,-2), 0.3, AMBER),
("BOX", (0,0), (-1,-1), 1, AMBER),
]))
reminder_header = Table([[Paragraph("★ KEY REMINDERS FOR AWAKE CRANIOTOMY",
style("remh", fontName="Helvetica-Bold", fontSize=9,
textColor=WHITE, leading=13))]],
colWidths=[CW])
reminder_header.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), AMBER),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story.append(reminder_header)
story.append(rem_tbl)
story.append(Spacer(1, 3*mm))
# ─────────────── FOOTER ───────────────────────────────────────────────────────
story.append(HRFlowable(width=CW, thickness=0.5, color=GREY_MID))
story.append(Spacer(1, 1*mm))
story.append(Paragraph(
"Orris Medical Reference | Awake Craniotomy Anesthesia Team Checklist | "
"Based on Miller's Anesthesia 10e, Barash Clinical Anesthesia 9e, Morgan & Mikhail 7e | June 2026 | "
"For educational and clinical reference use only — verify against local protocols and current guidelines.",
S_FOOTER
))
# ── Build ────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF written to: {OUTPUT}")
cd /home/daytona/workspace/awake-craniotomy && python generate_checklist.py 2>&1
ls -lh /home/daytona/workspace/awake-craniotomy/Awake_Craniotomy_Checklist.pdf
Awake Craniotomy Checklist
PDF Document · PDF
| Section | Color |
|---|---|
| Pre-operative Assessment | Dark navy |
| Equipment & Drug Preparation | Charcoal |
| Scalp Nerve Block (6 nerves table) | Teal |
| Sedation Agent Quick-Reference | Purple |
| Phase 1 — Asleep (Induction → Dural opening) | Navy |
| Phase 2 — Awake (Brain mapping) | Teal |
| Phase 3 — Re-sleep (Resection & Closure) | Dark slate |
| Complication Response Table | Red |
| Post-op Handover Points | Green |
| Key Reminders Box | Amber |
Explain pattern of stimulation TOF NEUROMUSCULAR STIMULATION Tof count ratio Fade on Tetanic stimulation In easy understanding way


| TOF Count | What it means | Approximate % receptors blocked |
|---|---|---|
| 4 of 4 | Moderate block / recovering | ~70-75% blocked |
| 3 of 4 | Deep surgical block | ~80% blocked |
| 2 of 4 | Deep block | ~85% blocked |
| 1 of 4 | Very deep block | ~90% blocked |
| 0 of 4 | Profound block (use PTC instead) | >90% blocked |
"As the effects of a nondepolarizing neuromuscular blocking drug deepen, the number of muscle responses will decline, T4 will be lost first, then T3, then T2 and finally T1. Regression of drug effect will follow the same pattern in reverse." - Barash 9e
"At a TOF ratio between 0.4 and 0.9, fade cannot be detected either visually or tactically. Therefore, objective monitoring devices are needed to reliably exclude residual paralysis." - Miller's Anesthesia 10e
"A characteristic of nondepolarizing drugs observed with partial nerve block is fade due to blocking of the presynaptic α3β2 acetylcholine receptors." - Barash 9e

| Feature | Nondepolarizing Block | Depolarizing Block (Suxamethonium) |
|---|---|---|
| TOF twitches | T4 disappears first, then T3, T2, T1 | All 4 twitches weaken equally |
| TOF fade | YES (T4 < T1) | NO (T4 = T1) |
| Tetanic stimulation | FADE (weakens over 5 sec) | SUSTAINED (no fade) |
| Post-tetanic facilitation | YES | NO |
| Phase II block (sux overdose) | N/A | FADE appears (like non-dep) |
"During a partial nondepolarizing block, the TOF ratio decreases (fades)... During a partial depolarizing block, no fade occurs in the TOF response and the TOF ratio remains 1.0. Fade in the TOF response after injection of succinylcholine signifies the development of a phase II block." - Miller's Anesthesia 10e
| Concept | Simple Meaning | Key Number |
|---|---|---|
| TOF | 4 pulses at 2 Hz; watch 4 twitches | Repeat every ≥10-15 sec |
| TOF Count | How many of the 4 twitches are present | Count 1-4 (0 = profound block) |
| TOF Ratio | T4 ÷ T1 height | Safe to extubate: ≥0.9 |
| Fade | T4 weaker than T1 (nondep. block) | Detectable by hand only if ratio <0.4 |
| No fade | All twitches equal height | Sux (depolarizing) - no fade |
| Tetanic stimulation | 50 Hz for 5 sec | Fade = nondep block. Sustained = dep block |
| Post-tetanic facilitation | Twitches bigger after tetanus | Only with nondep block |
| Residual paralysis | TOF ratio 0.4-0.9 - feels fine but is dangerous | Can't detect by hand - need a machine |
Pit them in pdf
mkdir -p /home/daytona/workspace/tof-nmb && ls /home/daytona/workspace/tof-nmb/
cd /home/daytona/workspace/tof-nmb && python3 -c " import urllib.request, os imgs = { 'tof_unblocked.png': 'https://cdn.orris.care/cdss_images/255397a14095e5d234e461b283b583729221de37a08283a6a5c9991fa08b0ee5.png', 'tof_nondep_dep.png': 'https://cdn.orris.care/cdss_images/c93916980d950d2b9e2a6c1a4415ae1676fa281327bb2236601268f33e80ea65.png', 'tetanic.png': 'https://cdn.orris.care/cdss_images/a7ede52ed2bf40ca3dc908cf5ebba2607e35ba1c21463e1e27992f45b74a2a1c.png', } for fname, url in imgs.items(): urllib.request.urlretrieve(url, fname) print(f'Downloaded {fname}: {os.path.getsize(fname)} bytes') "
~/tof-nmb/generate_tof_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.lib.colors import HexColor
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, Image, KeepTogether
)
import os
BASE = "/home/daytona/workspace/tof-nmb/"
OUTPUT = BASE + "TOF_Neuromuscular_Monitoring.pdf"
W, H = A4
LM = RM = 14*mm
TM = BM = 14*mm
CW = W - LM - RM
# ── Palette ─────────────────────────────────────────────────────────────────
NAVY = HexColor("#1B2A4A")
TEAL = HexColor("#0D7377")
TEAL_LT = HexColor("#E0F4F4")
PURPLE = HexColor("#5B2C8D")
PURP_LT = HexColor("#F3EEF9")
RED = HexColor("#C0392B")
RED_LT = HexColor("#FDECEA")
AMBER = HexColor("#D4700A")
AMBER_LT = HexColor("#FFF3E0")
GREEN = HexColor("#1A6B3C")
GREEN_LT = HexColor("#E8F5E9")
GREY_LT = HexColor("#F4F6F9")
GREY_MID = HexColor("#BDC3C7")
SLATE = HexColor("#2C3E50")
WHITE = colors.white
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=LM, rightMargin=RM, topMargin=TM, bottomMargin=BM,
title="Train-of-Four (TOF) Neuromuscular Monitoring",
author="Orris Medical Reference",
)
# ── Style factory ────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
S_TITLE = S("title", fontName="Helvetica-Bold", fontSize=18,
textColor=WHITE, leading=24, alignment=TA_CENTER)
S_SUBT = S("subt", fontName="Helvetica", fontSize=9,
textColor=HexColor("#C8DCF0"), leading=13, alignment=TA_CENTER)
S_H1 = S("h1", fontName="Helvetica-Bold", fontSize=11,
textColor=WHITE, leading=15, spaceAfter=0)
S_H2 = S("h2", fontName="Helvetica-Bold", fontSize=9.5,
textColor=WHITE, leading=13, spaceAfter=0)
S_BODY = S("body", fontName="Helvetica", fontSize=8.5,
textColor=HexColor("#1A1A2E"), leading=12.5, spaceAfter=0, alignment=TA_JUSTIFY)
S_BOLD = S("bold", fontName="Helvetica-Bold", fontSize=8.5,
textColor=HexColor("#1A1A2E"), leading=12.5, spaceAfter=0)
S_BULLET = S("bul", fontName="Helvetica", fontSize=8.3,
textColor=HexColor("#1A1A2E"), leading=12, leftIndent=8, spaceAfter=0)
S_WARN = S("warn", fontName="Helvetica-Bold", fontSize=8.3,
textColor=RED, leading=12, spaceAfter=0)
S_NOTE = S("note", fontName="Helvetica-Oblique", fontSize=7.5,
textColor=HexColor("#555566"), leading=10, alignment=TA_CENTER)
S_TH = S("th", fontName="Helvetica-Bold", fontSize=8,
textColor=WHITE, leading=11)
S_TD = S("td", fontName="Helvetica", fontSize=8,
textColor=HexColor("#1A1A2E"), leading=11)
S_TD_B = S("tdb", fontName="Helvetica-Bold", fontSize=8,
textColor=HexColor("#1A1A2E"), leading=11)
S_FOOTER = S("foot", fontName="Helvetica-Oblique", fontSize=6.5,
textColor=HexColor("#888899"), leading=9, alignment=TA_CENTER)
S_CAP = S("cap", fontName="Helvetica-Oblique", fontSize=7.5,
textColor=HexColor("#444455"), leading=10, alignment=TA_CENTER)
S_KEY = S("key", fontName="Helvetica-Bold", fontSize=8,
textColor=NAVY, leading=11.5, leftIndent=4)
# ── Helpers ──────────────────────────────────────────────────────────────────
def banner(text, sub=None, bg=NAVY, accent=TEAL):
rows = [[Paragraph(text, S_TITLE)]]
if sub:
rows.append([Paragraph(sub, S_SUBT)])
t = Table(rows, colWidths=[CW])
ts = [
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("LINEBELOW", (0,-1), (-1,-1), 3, accent),
]
t.setStyle(TableStyle(ts))
return t
def sec_hdr(text, bg=TEAL):
t = Table([[Paragraph(f"▌ {text}", S_H1)]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
def sub_hdr(text, bg=SLATE):
t = Table([[Paragraph(f" {text}", S_H2)]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return t
def body_box(paras, bg=GREY_LT):
rows = [[p] for p in paras]
t = Table(rows, colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return t
def two_col(left_items, right_items, bg_l=GREY_LT, bg_r=WHITE):
max_r = max(len(left_items), len(right_items))
rows = []
for i in range(max_r):
lp = left_items[i] if i < len(left_items) else Paragraph("", S_BODY)
rp = right_items[i] if i < len(right_items) else Paragraph("", S_BODY)
rows.append([lp, rp])
cw = CW / 2 - 2*mm
t = Table(rows, colWidths=[cw, cw])
t.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [GREY_LT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBETWEEN", (0,0), (1,-1), 0.4, GREY_MID),
("LINEBELOW", (0,-1), (-1,-1), 0.4, GREY_MID),
]))
return t
def info_table(data, col_widths, hdr_bg=NAVY, row_bg=GREY_LT):
header = [Paragraph(str(h), S_TH) for h in data[0]]
body = [[Paragraph(str(c), S_TD) for c in row] for row in data[1:]]
all_r = [header] + body
t = Table(all_r, colWidths=col_widths)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), hdr_bg),
("ROWBACKGROUNDS",(0,1), (-1,-1), [row_bg, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, GREY_MID),
]))
return t
def callout(text, bg=AMBER_LT, border=AMBER, style=None):
s = style or S_KEY
t = Table([[Paragraph(text, s)]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 1.2, border),
]))
return t
def img_block(path, caption, width_mm=130):
img = Image(path, width=width_mm*mm, height=None)
cap = Paragraph(caption, S_CAP)
t = Table([[img], [cap]], colWidths=[CW])
t.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("BACKGROUND", (0,0), (-1,-1), WHITE),
("BOX", (0,0), (-1,-1), 0.5, GREY_MID),
]))
return t
def bullet(txt, indent=0):
prefix = " " * indent
return Paragraph(f"{prefix}• {txt}", S_BULLET)
def warn(txt):
return Paragraph(f"⚠ {txt}", S_WARN)
# ────────────────────────────────────────────────────────────────────────────
story = []
# ── TITLE BANNER ─────────────────────────────────────────────────────────────
story.append(banner(
"TRAIN-OF-FOUR (TOF) NEUROMUSCULAR MONITORING",
sub="A Complete Easy-to-Understand Reference for Anaesthetists & Perioperative Teams",
bg=NAVY, accent=TEAL
))
story.append(Spacer(1, 5*mm))
# ── WHY SECTION ──────────────────────────────────────────────────────────────
story.append(sec_hdr("WHY DO WE MONITOR NEUROMUSCULAR BLOCKADE?", bg=NAVY))
story.append(body_box([
Paragraph(
"When a neuromuscular blocking drug (NMBD) is given, the muscle becomes paralysed. "
"The challenge is knowing <b>exactly how paralysed</b> the patient is at any given moment — "
"you cannot judge this visually. A peripheral nerve stimulator sends controlled electrical pulses "
"to a nerve (usually the <b>ulnar nerve</b> at the wrist), and we observe the resulting muscle "
"twitch (usually the <b>adductor pollicis / thumb</b>) to estimate the depth of block.",
S_BODY),
Spacer(1, 2*mm),
Paragraph(
"Think of it like pressing a doorbell repeatedly — the height of the 'ring' (twitch) tells you "
"how much signal is getting through the neuromuscular junction.",
S_BODY),
Spacer(1, 2*mm),
warn("As many as 30–40% of patients reversed with neostigmine have residual paralysis at extubation. "
"Objective TOF monitoring dramatically reduces this risk."),
], bg=GREY_LT))
story.append(Spacer(1, 4*mm))
# ── SECTION 1: TOF STIMULATION ────────────────────────────────────────────────
story.append(sec_hdr("1. TRAIN-OF-FOUR (TOF) STIMULATION — THE BASICS", bg=TEAL))
story.append(Spacer(1, 1*mm))
story.append(sub_hdr("What is it?", bg=SLATE))
story.append(body_box([
Paragraph(
"The nerve stimulator delivers <b>4 electrical pulses in rapid succession</b>, "
"each separated by 0.5 seconds (= 2 Hz frequency). This produces <b>4 twitches</b> "
"(T1, T2, T3, T4) in the monitored muscle.",
S_BODY),
Spacer(1,2*mm),
Paragraph("The train should <b>not</b> be repeated more frequently than every <b>10–15 seconds</b> "
"— repeating too soon causes physiological fade independent of any drug effect.", S_BODY),
], bg=TEAL_LT))
story.append(Spacer(1, 2*mm))
story.append(img_block(
BASE + "tof_unblocked.png",
"Fig. 1 — TOF in an unblocked patient: all 4 twitches are equal height → T₄/T₁ ratio = 1.0 "
"(Barash Clinical Anesthesia 9e)",
width_mm=110
))
story.append(Spacer(1, 3*mm))
story.append(sub_hdr("Normal state (no NMBD)", bg=GREEN))
story.append(body_box([
Paragraph("All 4 twitches are <b>equal height</b>. T1 = T2 = T3 = T4. TOF ratio = 1.0", S_BODY),
Paragraph("The nerve's ready acetylcholine (ACh) stores are plentiful — so even though each "
"pulse depletes a small amount, there is always enough left for a full-strength twitch.", S_BODY),
], bg=GREEN_LT))
story.append(Spacer(1, 2*mm))
story.append(sub_hdr("What happens with a nondepolarising NMBD (rocuronium, vecuronium, cisatracurium)?", bg=SLATE))
story.append(body_box([
Paragraph("The drug <b>competes with ACh</b> at postsynaptic nicotinic receptors AND blocks "
"<b>presynaptic α3β2 receptors</b> that normally signal the nerve terminal to "
"mobilise more ACh stores for the next impulse.", S_BODY),
Spacer(1,1*mm),
Paragraph("Result: each successive pulse releases progressively <b>less ACh</b>, and there are "
"fewer free receptors → <b>each twitch gets progressively weaker.</b> "
"This progressive weakening is called <b>FADE</b>.", S_BODY),
Spacer(1,1*mm),
Paragraph(
"<b>Analogy:</b> Imagine a bucket of water (ACh stores) and a partially clogged drain "
"(blocked receptors). Each time you press the button, less water gets through. "
"The first press = big splash (T1). By the 4th press = much smaller splash (T4). "
"The difference between them = <b>fade</b>.",
S_BODY),
], bg=GREY_LT))
story.append(Spacer(1, 3*mm))
story.append(img_block(
BASE + "tof_nondep_dep.png",
"Fig. 2 — TOF responses: Nondepolarising block shows progressive fade (T4 < T1). "
"Depolarising block (suxamethonium) shows all 4 twitches diminish equally — NO fade. "
"(Miller's Anesthesia 10e)",
width_mm=125
))
story.append(Spacer(1, 4*mm))
# ── SECTION 2: TOF COUNT ─────────────────────────────────────────────────────
story.append(sec_hdr("2. TOF COUNT", bg=PURPLE))
story.append(Spacer(1, 1*mm))
story.append(sub_hdr("Definition", bg=SLATE))
story.append(body_box([
Paragraph("Simply <b>count how many twitches you can feel or see</b> out of the 4. "
"This is the TOF count.", S_BODY),
Spacer(1,1*mm),
Paragraph(
"<b>Key rule:</b> As the block deepens, twitches disappear in <b>reverse order — "
"T4 goes first, then T3, then T2, then T1.</b> "
"During recovery they return in the <b>same reverse order: T1 first, T2, T3, then T4 last.</b>",
S_BOLD),
], bg=PURP_LT))
story.append(Spacer(1, 2*mm))
story.append(info_table([
["TOF Count", "Depth of Block", "Approx. % Receptors Occupied", "Clinical State"],
["4 / 4", "Minimal / Recovering", "~70–75%", "Surgical relaxation may still be present; DO NOT extubate without ratio ≥0.9"],
["3 / 4", "Moderate-Deep surgical block", "~80%", "Adequate for most surgery"],
["2 / 4", "Deep surgical block", "~85%", "Good relaxation"],
["1 / 4", "Very deep block", "~90%", "Use PTC to assess further"],
["0 / 4", "Profound block", ">90–95%", "Switch to Post-Tetanic Count (PTC)"],
], col_widths=[20*mm, 42*mm, 44*mm, 60*mm],
hdr_bg=PURPLE, row_bg=PURP_LT))
story.append(Spacer(1, 2*mm))
story.append(callout(
"★ Memory trick for deepening block: T4 → T3 → T2 → T1 disappear "
"| Recovery: T1 → T2 → T3 → T4 return | 'Last in, first out'",
bg=PURP_LT, border=PURPLE, style=S_KEY
))
story.append(Spacer(1, 4*mm))
# ── SECTION 3: TOF RATIO ─────────────────────────────────────────────────────
story.append(sec_hdr("3. TOF RATIO (T4/T1)", bg=HexColor("#0E6655")))
story.append(Spacer(1, 1*mm))
story.append(sub_hdr("Definition", bg=SLATE))
story.append(body_box([
Paragraph("When <b>all 4 twitches are present</b>, the TOF ratio is:", S_BODY),
Spacer(1,1*mm),
Paragraph(
"<font size=12><b>TOF Ratio = Height of T4 ÷ Height of T1</b></font>",
S("big", fontName="Helvetica-Bold", fontSize=11,
textColor=TEAL, alignment=TA_CENTER, leading=16)),
Spacer(1,1*mm),
Paragraph("Range: 0 (no T4) → 1.0 (T4 = T1, fully recovered)", S_BODY),
Paragraph("The <b>lower</b> the ratio, the <b>more residual block</b> remains.", S_BODY),
], bg=TEAL_LT))
story.append(Spacer(1, 2*mm))
story.append(sub_hdr("The critical threshold: TOF ratio ≥ 0.9", bg=GREEN))
story.append(body_box([
Paragraph(
"A TOF ratio of <b>≥ 0.9</b> is the internationally accepted threshold for safe extubation "
"and full neuromuscular recovery. Below 0.9 = <b>residual paralysis.</b>",
S_BOLD),
Spacer(1,1*mm),
Paragraph("Residual paralysis (TOF ratio 0.4–0.9) significantly increases the risk of:", S_BODY),
bullet("Upper airway obstruction"),
bullet("Aspiration (impaired pharyngeal and laryngeal reflexes)"),
bullet("Hypoxaemia after extubation"),
bullet("Unpleasant symptoms: diplopia, difficulty swallowing, generalised weakness"),
], bg=GREEN_LT))
story.append(Spacer(1, 2*mm))
story.append(sub_hdr("The clinical trap — why you CANNOT rely on your fingers alone", bg=RED))
story.append(body_box([
warn("Subjective (tactile/visual) assessment can only detect fade when TOF ratio is < 0.4."),
Spacer(1,1*mm),
Paragraph(
"Between TOF ratio <b>0.4 and 0.9</b> — the exact danger zone for residual paralysis — "
"<b>you cannot feel or see any difference by hand.</b> The patient feels 'recovered' "
"to your touch, but their airway reflexes and respiratory reserve are still impaired.",
S_BODY),
Spacer(1,1*mm),
Paragraph(
"<b>Solution:</b> Use an <b>objective quantitative monitoring device</b> (acceleromyography, "
"kinemyography, or electromyography) to measure the actual numeric ratio.",
S_BOLD),
], bg=RED_LT))
story.append(Spacer(1, 2*mm))
tof_ratio_table = info_table([
["TOF Ratio", "What You Can Feel/See", "Clinical Meaning"],
["1.0", "4 equal twitches", "Fully recovered — safe to extubate"],
["0.9–1.0", "Feels equal (cannot detect fade)", "⚠ Target threshold — need device to confirm"],
["0.7–0.9", "Cannot feel fade by hand", "⚠ Residual paralysis — DO NOT extubate"],
["0.4–0.7", "Usually cannot feel fade", "⚠ Significant residual block"],
["<0.4", "Fade detectable by hand", "Moderate–deep block"],
["0", "Only 1–3 twitches present", "TOF count used instead of ratio"],
], col_widths=[25*mm, 65*mm, 76*mm],
hdr_bg=HexColor("#0E6655"), row_bg=TEAL_LT)
story.append(tof_ratio_table)
story.append(Spacer(1, 4*mm))
# ── SECTION 4: FADE ──────────────────────────────────────────────────────────
story.append(sec_hdr("4. FADE — MECHANISM AND MEANING", bg=AMBER))
story.append(Spacer(1, 1*mm))
story.append(sub_hdr("What exactly is fade?", bg=SLATE))
story.append(body_box([
Paragraph(
"<b>Fade</b> = the progressive weakening of successive muscle twitches during repeated "
"stimulation. It is the <b>hallmark of nondepolarising (competitive) block</b> and is "
"<b>absent in normal depolarising (phase I) block.</b>",
S_BODY),
], bg=AMBER_LT))
story.append(Spacer(1, 1*mm))
story.append(sub_hdr("Two mechanisms that cause fade", bg=SLATE))
left_items = [
Paragraph("<b>1. Postsynaptic (receptor depletion effect)</b>", S_BOLD),
Spacer(1,1*mm),
bullet("The drug occupies postsynaptic nicotinic ACh receptors at the muscle end-plate."),
bullet("Each successive nerve impulse releases slightly less ACh (stores deplete)."),
bullet("With fewer free receptors AND less ACh → each successive twitch is weaker."),
bullet("This creates the characteristic staircase descent: T1 > T2 > T3 > T4."),
]
right_items = [
Paragraph("<b>2. Presynaptic (mobilisation failure)</b>", S_BOLD),
Spacer(1,1*mm),
bullet("Nondepolarising NMBDs also block presynaptic neuronal-subtype α3β2 receptors."),
bullet("These receptors normally act as a feedback sensor: 'We're running low on ACh — mobilise more!'"),
bullet("Block them → the nerve can't replenish its ACh store fast enough → accelerated depletion."),
bullet("This is considered the MAIN driver of fade, especially during TOF and tetanic stimulation."),
]
story.append(two_col(left_items, right_items))
story.append(Spacer(1, 3*mm))
story.append(callout(
"★ Key concept: FADE is a presynaptic phenomenon at its core — caused by blockade of "
"presynaptic ACh mobilisation receptors, worsened by postsynaptic receptor competition. "
"No fade = no presynaptic involvement = depolarising (suxamethonium) block.",
bg=AMBER_LT, border=AMBER
))
story.append(Spacer(1, 4*mm))
# ── SECTION 5: TETANIC STIMULATION ───────────────────────────────────────────
story.append(sec_hdr("5. TETANIC STIMULATION AND TETANIC FADE", bg=RED))
story.append(Spacer(1, 1*mm))
story.append(sub_hdr("What is tetanic stimulation?", bg=SLATE))
story.append(body_box([
Paragraph(
"Instead of 4 spaced pulses, the stimulator fires at <b>50 Hz (50 pulses per second) "
"continuously for 5 seconds</b>. This is an intense, high-frequency stimulus that rapidly "
"demands large amounts of ACh release.",
S_BODY),
Spacer(1,1*mm),
Paragraph(
"<b>Normal response (no drug):</b> One strong, <b>sustained</b> muscle contraction throughout "
"the 5 seconds — called a tetanic contraction. Feels like one hard squeeze.",
S_BODY),
Spacer(1,1*mm),
Paragraph(
"<b>With nondepolarising block:</b> The contraction <b>starts strong but fades</b> — the "
"muscle weakens visibly partway through. This is <b>tetanic fade</b>. "
"This is because ACh stores are depleted much faster at 50 Hz than at the 2 Hz of TOF, "
"and presynaptic mobilisation failure becomes even more apparent.",
S_BODY),
Spacer(1,1*mm),
Paragraph(
"<b>With depolarising block (suxamethonium — phase I):</b> The tetanic response is <b>fully "
"sustained</b> — no fade. The drug works by persistent depolarisation (not competitive "
"blockade), so presynaptic mobilisation is not impaired.",
S_BODY),
], bg=RED_LT))
story.append(Spacer(1, 2*mm))
story.append(img_block(
BASE + "tetanic.png",
"Fig. 3 — Tetanic stimulation (50 Hz / 5 s): Control = sustained contraction. "
"Moderate nondep. block = fade + post-tetanic facilitation. "
"Moderate dep. block = sustained, no post-tetanic facilitation. (Miller's Anesthesia 10e)",
width_mm=130
))
story.append(Spacer(1, 2*mm))
story.append(sub_hdr("Post-Tetanic Facilitation and Post-Tetanic Count (PTC)", bg=SLATE))
story.append(body_box([
Paragraph(
"After tetanic stimulation, the nerve terminal has been intensely 'revved up' and "
"temporarily releases <b>more ACh than usual</b> for the next few minutes. "
"If you then apply single twitches, they are temporarily <b>bigger than before</b> — "
"this is called <b>post-tetanic facilitation</b>.",
S_BODY),
Spacer(1,1*mm),
Paragraph("<b>Post-Tetanic Count (PTC)</b> — used when block is <b>so deep that TOF = 0</b>:", S_BOLD),
Spacer(1,1*mm),
bullet("Apply 50 Hz tetanus for 5 seconds"),
bullet("Wait 3 seconds"),
bullet("Apply single twitches at 1 Hz and count how many appear"),
bullet("Fewer PTC twitches = deeper block. PTC ≥ 10 predicts return of TOF count 1 within minutes."),
Spacer(1,1*mm),
warn("Post-tetanic facilitation occurs ONLY with nondepolarising block. "
"It does NOT occur with suxamethonium phase I block — another way to distinguish the two."),
], bg=GREY_LT))
story.append(Spacer(1, 4*mm))
# ── SECTION 6: DEPOLARISING vs NON-DEPOLARISING COMPARISON ───────────────────
story.append(sec_hdr("6. NONDEPOLARISING vs DEPOLARISING BLOCK — SIDE-BY-SIDE", bg=NAVY))
story.append(Spacer(1, 1*mm))
story.append(info_table([
["Feature", "Nondepolarising Block\n(rocuronium, vecuronium, cisatracurium)",
"Depolarising Block — Phase I\n(suxamethonium)"],
["Mechanism", "Competitive ACh receptor antagonism\n+ presynaptic α3β2 blockade",
"Persistent receptor depolarisation\n(agonist-type binding)"],
["TOF twitches", "T4 disappears first → T3 → T2 → T1",
"All 4 twitches diminish equally"],
["TOF fade (T4/T1)", "YES — T4 < T1 (ratio < 1.0)",
"NO — T4 = T1 (ratio stays 1.0)"],
["Tetanic stimulation", "FADE — contraction weakens over 5 sec",
"SUSTAINED — no fade"],
["Post-tetanic facilitation","YES — twitches larger after tetanus",
"NO — no change after tetanus"],
["Phase II block (sux)", "N/A",
"After large/repeated doses: FADE appears\n(behaves like nondep. block)"],
["Reversal", "Neostigmine (if TOF≥2), sugammadex (rocuronium/vecuronium)",
"Wait for pseudocholinesterase metabolism"],
], col_widths=[40*mm, 76*mm, 50*mm],
hdr_bg=NAVY, row_bg=GREY_LT))
story.append(Spacer(1, 4*mm))
# ── SECTION 7: DEPTH OF BLOCK OVERVIEW ───────────────────────────────────────
story.append(sec_hdr("7. DEPTH OF BLOCK — COMPLETE OVERVIEW", bg=HexColor("#6C3483")))
story.append(Spacer(1, 1*mm))
story.append(info_table([
["Depth", "TOF Count", "TOF Ratio", "PTC", "Clinical Meaning / Action"],
["Intense", "0", "N/A", "0", "Maximum block — use for intubation, complex laparoscopy"],
["Deep", "0", "N/A", "1–5", "Cannot reverse — wait or use sugammadex"],
["Deep-moderate", "0", "N/A", "6–10", "Approaching return of TOF; plan reversal timing"],
["Moderate", "1–3", "Not useable", "N/A", "Surgical relaxation; can reverse with sugammadex; neostigmine needs TOF≥2"],
["Shallow", "4", "0.1–0.4", "N/A", "Fade visible by hand; neostigmine reversal possible"],
["Minimal", "4", "0.4–0.9", "N/A", "⚠ RESIDUAL PARALYSIS — looks OK by hand, NOT safe"],
["Full recovery", "4", "≥ 0.9", "N/A", "Safe to extubate — MUST use device to confirm"],
], col_widths=[28*mm, 22*mm, 22*mm, 20*mm, 74*mm],
hdr_bg=HexColor("#6C3483"), row_bg=PURP_LT))
story.append(Spacer(1, 4*mm))
# ── SECTION 8: LIMITATIONS ───────────────────────────────────────────────────
story.append(sec_hdr("8. LIMITATIONS OF SUBJECTIVE TOF MONITORING", bg=SLATE))
story.append(Spacer(1, 1*mm))
lim_left = [
Paragraph("<b>What you CANNOT detect by hand:</b>", S_BOLD),
Spacer(1,1*mm),
warn("Fade between TOF ratio 0.4 and 0.9 — the exact zone of dangerous residual paralysis."),
Spacer(1,1*mm),
bullet("Subjective fade detection accurate only at ratio < 0.4"),
bullet("Even 100 Hz tetanus only detects fade up to ratio ~0.4–0.5"),
bullet("Double-burst stimulation (DBS) is marginally better but still unreliable above 0.6"),
bullet("Postoperative residual paralysis rate: 30–40% with neostigmine reversal"),
]
lim_right = [
Paragraph("<b>What OBJECTIVE devices provide:</b>", S_BOLD),
Spacer(1,1*mm),
bullet("Acceleromyography (AMG): measures thumb acceleration — most common portable device"),
bullet("Electromyography (EMG): measures electrical signal — gold standard"),
bullet("Kinemyography (KMG): measures bending of finger — found in TOF-Watch devices"),
Spacer(1,1*mm),
Paragraph(
"Guidelines from Canada, France, Spain, Australia now <b>advocate quantitative monitoring</b> "
"before extubation of every patient receiving NMBDs.",
S_BODY),
]
story.append(two_col(lim_left, lim_right))
story.append(Spacer(1, 4*mm))
# ── QUICK REFERENCE SUMMARY ───────────────────────────────────────────────────
story.append(sec_hdr("QUICK REFERENCE SUMMARY — EVERYTHING AT A GLANCE", bg=TEAL))
story.append(Spacer(1, 1*mm))
story.append(info_table([
["Concept", "Simple Meaning", "Key Number / Fact"],
["TOF Stimulation", "4 pulses at 2 Hz → 4 twitches (T1–T4)", "Repeat every ≥10–15 sec"],
["TOF Count", "How many of the 4 twitches are present", "0 = profound; 4 = at least moderate recovery"],
["TOF Ratio (T4/T1)", "T4 height ÷ T1 height", "≥ 0.9 = safe to extubate"],
["Fade", "T4 weaker than T1 (nondep. block sign)", "Detectable by hand only if ratio < 0.4"],
["No Fade", "All twitches equal height", "Suxamethonium phase I — no presynaptic blockade"],
["Tetanic Stimulation", "50 Hz for 5 sec — demands heavy ACh release", "Fade = nondep block; Sustained = dep block"],
["Post-tetanic Facilitation", "Twitches bigger immediately after tetanus", "Only with nondepolarising block; not with sux"],
["PTC (Post-Tetanic Count)", "Count twitches after tetanus when TOF = 0", "PTC ≥ 10 → TOF count 1 will return soon"],
["Residual Paralysis", "TOF ratio 0.4–0.9 — feels recovered, IS NOT", "Cannot detect by hand — need objective device"],
], col_widths=[42*mm, 80*mm, 44*mm],
hdr_bg=TEAL, row_bg=TEAL_LT))
story.append(Spacer(1, 3*mm))
# ── KEY REMINDERS ─────────────────────────────────────────────────────────────
reminders = [
"TOF ratio ≥ 0.9 is the ONLY reliable threshold for safe extubation — you need an objective device to confirm it.",
"Fade is the fingerprint of nondepolarising block. No fade = depolarising (suxamethonium) or fully recovered.",
"Subjective (hand) monitoring misses residual paralysis in the 0.4–0.9 ratio range — the most dangerous zone.",
"T4 is lost first as block deepens; T4 returns last during recovery. Use this to track the curve of block.",
"Tetanic stimulation is more sensitive than TOF for detecting small amounts of residual block — but it can alter subsequent monitoring for several minutes, so use it sparingly.",
]
rem_header = Table([[Paragraph("★ CRITICAL REMINDERS", S("remh", fontName="Helvetica-Bold", fontSize=9, textColor=WHITE, leading=13))]],
colWidths=[CW])
rem_header.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1), AMBER),
("TOPPADDING",(0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING",(0,0),(-1,-1), 8),
]))
story.append(rem_header)
rem_rows = [[Paragraph(f"★ {r}", S_KEY)] for r in reminders]
rem_tbl = Table(rem_rows, colWidths=[CW])
rem_tbl.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1), AMBER_LT),
("TOPPADDING",(0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING",(0,0),(-1,-1), 8),
("RIGHTPADDING",(0,0),(-1,-1), 8),
("LINEBELOW",(0,0),(-1,-2), 0.3, AMBER),
("BOX",(0,0),(-1,-1), 1, AMBER),
]))
story.append(rem_tbl)
story.append(Spacer(1, 3*mm))
# ── FOOTER ────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=CW, thickness=0.5, color=GREY_MID))
story.append(Spacer(1, 1*mm))
story.append(Paragraph(
"Orris Medical Reference | Train-of-Four (TOF) Neuromuscular Monitoring | "
"Sources: Miller's Anesthesia 10e (Ch. 39), Barash Clinical Anesthesia 9e (Ch. 21), "
"Morgan & Mikhail Clinical Anesthesiology 7e | June 2026 | "
"For educational and clinical reference use only — verify against local protocols.",
S_FOOTER
))
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF written: {OUTPUT}")
print(f"File size: {os.path.getsize(OUTPUT):,} bytes")
cd /home/daytona/workspace/tof-nmb && python3 generate_tof_pdf.py 2>&1
~/tof-nmb/generate_tof_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tof-nmb/generate_tof_pdf.py'
~/tof-nmb/generate_tof_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tof-nmb/generate_tof_pdf.py'
~/tof-nmb/generate_tof_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tof-nmb/generate_tof_pdf.py'
~/tof-nmb/generate_tof_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tof-nmb/generate_tof_pdf.py'
~/tof-nmb/generate_tof_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tof-nmb/generate_tof_pdf.py'
~/tof-nmb/generate_tof_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/tof-nmb/generate_tof_pdf.py'
cd /home/daytona/workspace/tof-nmb && python3 generate_tof_pdf.py 2>&1
TOF Neuromuscular Monitoring
PDF Document · PDF
| Section | Content |
|---|---|
| Why we monitor | Clinical rationale, residual paralysis incidence (30-40%) |
| Section 1 - TOF Stimulation | How it works, the bucket-of-ACh analogy, includes the TOF pattern diagram (Fig. 1 & 2) |
| Section 2 - TOF Count | Full table: count 0-4 vs receptor occupancy vs clinical state; memory trick |
| Section 3 - TOF Ratio | Formula, critical 0.9 threshold, the danger zone (0.4-0.9), why your fingers lie |
| Section 4 - Fade | Both mechanisms explained (postsynaptic + presynaptic α3β2); analogy |
| Section 5 - Tetanic Stimulation | 50 Hz/5 sec, fade vs sustained, post-tetanic facilitation, PTC; includes Fig. 3 |
| Section 6 - Nondep vs Dep comparison | Full side-by-side table: fade, tetanus, PTC, reversal |
| Section 7 - Depth of Block | Intense → deep → moderate → shallow → full recovery with all monitoring parameters |
| Section 8 - Limitations | Why subjective monitoring fails; objective device types |
| Quick Reference Summary | All concepts in one concise table |
| Critical Reminders | 5 gold-box key points |