Content for ecg
mkdir -p /home/daytona/workspace/ecg-presentation && ls /home/daytona/workspace/ecg-presentation
~/ecg-presentation/build.js
const pptxgen = require("pptxgenjs");
let pres = new pptxgen();
pres.layout = 'LAYOUT_16x9';
pres.author = 'Medical Education';
pres.title = 'ECG Basics & Waveforms';
// ─── COLOUR PALETTE ───────────────────────────────────────────────
const C = {
navy: "0B1F4B", // dominant dark background
midBlue: "1A3A6B", // section bg
accent: "00C2CB", // teal accent (ECG trace colour)
gold: "F5A623", // highlight / label colour
white: "FFFFFF",
lightGrey: "E8EDF5",
textBody: "D0DCF0",
red: "E8334A",
green: "27AE60",
};
// ─── HELPERS ──────────────────────────────────────────────────────
function darkSlide(slide) {
slide.background = { color: C.navy };
}
function midSlide(slide) {
slide.background = { color: C.midBlue };
}
function lightSlide(slide) {
slide.background = { color: C.lightGrey };
}
function heading(slide, text, y = 0.22) {
slide.addText(text, {
x: 0.5, y, w: 9, h: 0.6,
fontSize: 28, bold: true, color: C.accent,
fontFace: "Calibri", margin: 0,
});
}
function subheading(slide, text, y = 0.88) {
slide.addText(text, {
x: 0.5, y, w: 9, h: 0.45,
fontSize: 17, bold: true, color: C.gold,
fontFace: "Calibri", margin: 0,
});
}
function bodyText(slide, items, x, y, w, h, opts = {}) {
const arr = items.map((t, i) => ({
text: t,
options: { bullet: true, breakLine: i < items.length - 1, fontSize: 14, color: C.textBody, fontFace: "Calibri", ...opts }
}));
slide.addText(arr, { x, y, w, h });
}
function accentBox(slide, x, y, w, h, text, fontSize = 13) {
slide.addShape(pres.ShapeType.rect, {
x, y, w, h,
fill: { color: "0D2A5C" },
line: { color: C.accent, width: 1.5 },
});
slide.addText(text, {
x: x + 0.08, y: y + 0.07, w: w - 0.16, h: h - 0.14,
fontSize, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0,
});
}
function labeledBox(slide, label, value, x, y, w = 2.8) {
slide.addShape(pres.ShapeType.rect, {
x, y, w, h: 0.72,
fill: { color: C.midBlue },
line: { color: C.accent, width: 1.5 },
});
slide.addText(label, { x: x + 0.1, y: y + 0.04, w: w - 0.2, h: 0.3, fontSize: 11, color: C.gold, bold: true, fontFace: "Calibri", margin: 0 });
slide.addText(value, { x: x + 0.1, y: y + 0.33, w: w - 0.2, h: 0.3, fontSize: 12, color: C.white, fontFace: "Calibri", margin: 0 });
}
function footerSource(slide, source) {
slide.addText(source, {
x: 0.3, y: 5.2, w: 9.4, h: 0.3,
fontSize: 8, color: "5E7A9E", italic: true, fontFace: "Calibri", margin: 0,
});
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 1 – TITLE
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
// decorative ECG-like line
sl.addShape(pres.ShapeType.line, { x: 0, y: 2.9, w: 10, h: 0, line: { color: C.accent, width: 1, dashType: "dash" } });
sl.addText("ECG BASICS &", {
x: 0.6, y: 1.0, w: 8.8, h: 0.85,
fontSize: 52, bold: true, color: C.white, charSpacing: 4,
fontFace: "Calibri", align: "center", margin: 0,
});
sl.addText("WAVEFORMS", {
x: 0.6, y: 1.85, w: 8.8, h: 0.85,
fontSize: 52, bold: true, color: C.accent, charSpacing: 8,
fontFace: "Calibri", align: "center", margin: 0,
});
sl.addText("A Foundation Guide for Medical Students", {
x: 1, y: 3.05, w: 8, h: 0.45,
fontSize: 18, color: C.textBody, fontFace: "Calibri", align: "center", italic: true, margin: 0,
});
// topics row
const topics = ["Cardiac Electricity", "Conduction System", "ECG Waveforms", "Key Intervals", "Normal Values"];
topics.forEach((t, i) => {
sl.addShape(pres.ShapeType.rect, { x: 0.22 + i * 1.93, y: 3.75, w: 1.7, h: 0.52, fill: { color: C.midBlue }, line: { color: C.accent, width: 1 } });
sl.addText(t, { x: 0.22 + i * 1.93, y: 3.75, w: 1.7, h: 0.52, fontSize: 10, color: C.accent, fontFace: "Calibri", align: "center", valign: "middle", margin: 0 });
});
sl.addText("Sources: Guyton & Hall Medical Physiology 14e · Goldman-Cecil Medicine 27e · Costanzo Physiology 7e · Medical Physiology (Boron & Boulpaep)", {
x: 0.4, y: 5.15, w: 9.2, h: 0.32, fontSize: 8, color: "4A6080", italic: true, fontFace: "Calibri", align: "center", margin: 0,
});
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 2 – WHAT IS AN ECG?
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "What is an ECG?");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
// left column – definition
subheading(sl, "Definition", 1.0);
bodyText(sl, [
"An electrocardiogram (ECG / EKG) records the electrical activity of the heart from the body surface.",
"When a cardiac impulse passes through the heart, small electrical currents spread to the skin surface.",
"Electrodes placed on opposite sides of the heart detect potential differences — the tracing is the ECG.",
"Provides information on heart rate, rhythm, conduction, and myocardial status.",
], 0.5, 1.42, 4.6, 2.5);
// right column – what it detects
subheading(sl, "What It Detects", 1.0);
const detect = [
["Depolarization", "Electrical activation spreading through atria and ventricles"],
["Repolarization", "Electrical recovery after contraction"],
["Timing", "Duration of conduction intervals"],
["Axis", "Direction of electrical wave fronts"],
];
detect.forEach(([lbl, val], i) => {
sl.addShape(pres.ShapeType.rect, { x: 5.45, y: 1.35 + i * 0.88, w: 4.1, h: 0.75, fill: { color: "0D2A5C" }, line: { color: C.accent, width: 1 } });
sl.addText(lbl, { x: 5.55, y: 1.38 + i * 0.88, w: 3.9, h: 0.28, fontSize: 12, color: C.gold, bold: true, fontFace: "Calibri", margin: 0 });
sl.addText(val, { x: 5.55, y: 1.63 + i * 0.88, w: 3.9, h: 0.38, fontSize: 11, color: C.white, fontFace: "Calibri", margin: 0 });
});
// quote box
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 4.1, w: 9, h: 0.82, fill: { color: C.midBlue }, line: { color: C.gold, width: 1.5 } });
sl.addText([
{ text: "Key concept: ", options: { bold: true, color: C.gold } },
{ text: "The ECG records both depolarization and repolarization waves. Current flows — and is detectable — only when part of the myocardium is depolarized while another part is still polarized.", options: { color: C.white } }
], { x: 0.7, y: 4.15, w: 8.6, h: 0.72, fontSize: 12.5, fontFace: "Calibri", valign: "middle" });
footerSource(sl, "Guyton & Hall, Fundamentals of Electrocardiography, p.142");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 3 – CARDIAC CONDUCTION SYSTEM
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "Cardiac Conduction System");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "Sequential Activation Pathway", 1.0);
// Pathway boxes with arrows
const steps = [
{ num: "1", title: "SA Node", desc: "Dominant pacemaker in right atrium near SVC. Spontaneous depolarization at highest rate (~60-100 bpm).", color: C.accent },
{ num: "2", title: "Internodal Pathways / Bachmann Bundle", desc: "Spread through right & left atria. Bachmann bundle speeds conduction to left atrium. → P wave on ECG.", color: C.gold },
{ num: "3", title: "AV Node", desc: "Physiological conduction delay (~0.1 s). ONLY normal electrical connection between atria and ventricles. → PR segment.", color: "7B68EE" },
{ num: "4", title: "Bundle of His", desc: "Exits AV node. Specialized rapid-conduction tissue.", color: C.green },
{ num: "5", title: "Bundle Branches & Purkinje System", desc: "Right + Left bundle branches (LBB divides into anterior & posterior fascicles). → QRS complex.", color: "FF7F50" },
];
steps.forEach((s, i) => {
const row = i < 3 ? i : i;
const x = 0.4;
const y = 1.4 + i * 0.77;
sl.addShape(pres.ShapeType.rect, { x, y, w: 9.2, h: 0.66, fill: { color: "0D2A5C" }, line: { color: s.color, width: 1.5 } });
sl.addText(s.num, { x: x + 0.06, y: y + 0.06, w: 0.36, h: 0.54, fontSize: 16, bold: true, color: s.color, fontFace: "Calibri", align: "center", valign: "middle", margin: 0 });
sl.addText(s.title, { x: x + 0.5, y: y + 0.04, w: 2.5, h: 0.3, fontSize: 12, bold: true, color: s.color, fontFace: "Calibri", margin: 0 });
sl.addText(s.desc, { x: x + 0.5, y: y + 0.31, w: 8.5, h: 0.28, fontSize: 10.5, color: C.textBody, fontFace: "Calibri", margin: 0 });
});
footerSource(sl, "Goldman-Cecil Medicine 27e, NORMAL FUNCTION AND ELECTROCARDIOGRAM, p.519 · Ganong's Review of Medical Physiology 26e");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 4 – THE NORMAL ECG WAVEFORM (text-diagram)
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "The Normal ECG Waveform");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "Components of One Cardiac Cycle", 1.0);
// ASCII-style ECG diagram using shapes
// Baseline
const bx = 0.5, by = 3.1, bw = 9;
sl.addShape(pres.ShapeType.line, { x: bx, y: by, w: bw, h: 0, line: { color: "3A5A8A", width: 1.2 } });
// Draw ECG trace segments using lines
// isoelectric → P up → P down → PR isoelectric → Q down → R up big → S down → S up → ST → T up → T down → isoelectric
const traceColor = C.accent;
const lw = 2.5;
// Segment data: [x1, y1, x2, y2] in inches relative to slide
const segs = [
// flat before P
[0.5, 3.1, 1.1, 3.1],
// P wave up
[1.1, 3.1, 1.3, 2.78],
// P wave down
[1.3, 2.78, 1.55, 3.1],
// PR segment flat
[1.55, 3.1, 2.1, 3.1],
// Q down
[2.1, 3.1, 2.28, 3.35],
// R up
[2.28, 3.35, 2.52, 1.95],
// S down
[2.52, 1.95, 2.75, 3.38],
// Return baseline (J point)
[2.75, 3.38, 2.95, 3.1],
// ST segment
[2.95, 3.1, 3.6, 3.1],
// T wave up
[3.6, 3.1, 3.95, 2.65],
// T wave down
[3.95, 2.65, 4.35, 3.1],
// post-T flat
[4.35, 3.1, 5.0, 3.1],
];
segs.forEach(([x1, y1, x2, y2]) => {
const dx = x2 - x1, dy = y2 - y1;
const w = Math.abs(dx) < 0.01 ? 0.01 : dx;
const h = Math.abs(dy) < 0.01 ? 0.01 : dy;
sl.addShape(pres.ShapeType.line, { x: x1, y: Math.min(y1, y2), w: Math.abs(dx) || 0.01, h: Math.abs(dy) || 0.01, line: { color: traceColor, width: lw } });
});
// Labels
const labels = [
{ text: "P", x: 1.2, y: 2.55, color: C.gold },
{ text: "Q", x: 2.12, y: 3.42, color: C.gold },
{ text: "R", x: 2.45, y: 1.72, color: C.gold },
{ text: "S", x: 2.72, y: 3.5, color: C.gold },
{ text: "T", x: 3.88, y: 2.44, color: C.gold },
];
labels.forEach(lb => {
sl.addText(lb.text, { x: lb.x, y: lb.y, w: 0.4, h: 0.35, fontSize: 16, bold: true, color: lb.color, fontFace: "Calibri", align: "center", margin: 0 });
});
// Interval annotations (braces / lines)
// PR interval
sl.addShape(pres.ShapeType.line, { x: 1.1, y: 3.62, w: 1.0, h: 0, line: { color: C.green, width: 1.5 } });
sl.addText("PR interval", { x: 1.0, y: 3.72, w: 1.2, h: 0.25, fontSize: 9, color: C.green, fontFace: "Calibri", align: "center", margin: 0 });
// QRS interval
sl.addShape(pres.ShapeType.line, { x: 2.1, y: 3.62, w: 0.85, h: 0, line: { color: C.red, width: 1.5 } });
sl.addText("QRS", { x: 2.05, y: 3.72, w: 0.95, h: 0.25, fontSize: 9, color: C.red, fontFace: "Calibri", align: "center", margin: 0 });
// QT interval
sl.addShape(pres.ShapeType.line, { x: 2.1, y: 3.95, w: 2.25, h: 0, line: { color: "7B68EE", width: 1.5 } });
sl.addText("QT interval", { x: 2.1, y: 4.05, w: 2.25, h: 0.25, fontSize: 9, color: "7B68EE", fontFace: "Calibri", align: "center", margin: 0 });
// ST segment label
sl.addShape(pres.ShapeType.line, { x: 2.95, y: 3.62, w: 0.65, h: 0, line: { color: C.gold, width: 1.5 } });
sl.addText("ST", { x: 2.9, y: 3.72, w: 0.75, h: 0.25, fontSize: 9, color: C.gold, fontFace: "Calibri", align: "center", margin: 0 });
// Right panel – brief descriptions
const descs = [
{ wave: "P wave", def: "Atrial depolarization", col: C.accent },
{ wave: "QRS complex", def: "Ventricular depolarization", col: C.accent },
{ wave: "T wave", def: "Ventricular repolarization", col: C.accent },
{ wave: "PR interval", def: "Onset P → onset QRS; AV node delay", col: C.green },
{ wave: "ST segment", def: "End QRS → start T; J point to T", col: C.gold },
{ wave: "QT interval", def: "Ventricular depolarization + repolarization", col: "7B68EE" },
];
descs.forEach((d, i) => {
sl.addText([
{ text: d.wave + ": ", options: { bold: true, color: d.col, fontSize: 12, fontFace: "Calibri" } },
{ text: d.def, options: { color: C.textBody, fontSize: 12, fontFace: "Calibri" } },
], { x: 5.2, y: 1.15 + i * 0.63, w: 4.4, h: 0.5 });
});
footerSource(sl, "Guyton & Hall 14e p.142-143 · Costanzo Physiology 7e p.148 · Medical Physiology Boron & Boulpaep p.732");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 5 – P WAVE
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "P Wave — Atrial Depolarization");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "Physiology", 1.02);
bodyText(sl, [
"Represents electrical depolarization of the atria (right, then left).",
"Originates from SA node in the high lateral right atrium near the superior vena cava.",
"Electrical wave front spreads through atria via internodal pathways; Bachmann bundle carries it to the left atrium.",
"Atrial muscle contraction begins just AFTER the P wave.",
"Atrial repolarization (atrial T wave) is buried within the QRS complex and NOT visible on the normal ECG.",
], 0.5, 1.4, 5.5, 2.7);
subheading(sl, "Normal Parameters", 1.02);
const pParams = [
["Duration", "< 0.12 s (< 3 small boxes)"],
["Amplitude", "< 2.5 mm in limb leads"],
["Morphology", "Smooth, rounded, upright in lead II"],
["Axis", "0° to +75°"],
];
pParams.forEach(([lbl, val], i) => {
labeledBox(sl, lbl, val, 5.7, 1.35 + i * 0.82);
});
// Key clinical note
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 4.2, w: 9, h: 0.82, fill: { color: "0D2A5C" }, line: { color: C.gold, width: 1.5 } });
sl.addText([
{ text: "Clinical tip: ", options: { bold: true, color: C.gold } },
{ text: "If P wave duration increases (e.g. >0.12 s, broad notched P), suspect left atrial enlargement (P mitrale). Tall peaked P >2.5 mm in lead II suggests right atrial enlargement (P pulmonale).", options: { color: C.white } }
], { x: 0.7, y: 4.25, w: 8.6, h: 0.72, fontSize: 12, fontFace: "Calibri", valign: "middle" });
footerSource(sl, "Guyton & Hall 14e · Medical Physiology Boron & Boulpaep p.732 · Goldman-Cecil Medicine 27e p.535");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 6 – PR INTERVAL
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "PR Interval — AV Node Conduction");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "Definition & Physiology", 1.02);
bodyText(sl, [
"Measured from the BEGINNING of the P wave to the BEGINNING of the QRS complex.",
"Includes: P wave + PR segment (isoelectric flat line).",
"The isoelectric PR segment corresponds to conduction through the AV node.",
"The AV node introduces a physiological delay (~0.1 s) — essential to allow atrial filling of ventricles.",
"AV node is the ONLY normal electrical connection between atria and ventricles.",
], 0.5, 1.4, 5.5, 2.7);
subheading(sl, "Normal Values & Autonomic Control", 1.02);
accentBox(sl, 5.7, 1.35, 3.9, 0.72, "Normal PR: 0.12 – 0.20 s\n(3 – 5 small boxes)", 13);
accentBox(sl, 5.7, 2.15, 3.9, 0.72, "Sympathetic ↑ → PR shortens\n(faster AV conduction)", 12);
accentBox(sl, 5.7, 2.95, 3.9, 0.72, "Parasympathetic ↑ → PR lengthens\n(slower AV conduction)", 12);
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 4.2, w: 9, h: 0.82, fill: { color: "0D2A5C" }, line: { color: C.red, width: 1.5 } });
sl.addText([
{ text: "Abnormal: ", options: { bold: true, color: C.red } },
{ text: "PR > 0.20 s = First-degree AV block. PR < 0.12 s = pre-excitation (e.g. WPW syndrome) or junctional rhythm.", options: { color: C.white } }
], { x: 0.7, y: 4.25, w: 8.6, h: 0.72, fontSize: 12, fontFace: "Calibri", valign: "middle" });
footerSource(sl, "Medical Physiology Boron & Boulpaep p.809 · Costanzo Physiology 7e p.149 · Goldman-Cecil Medicine 27e");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 7 – QRS COMPLEX
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "QRS Complex — Ventricular Depolarization");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
// Left column
subheading(sl, "Components", 1.02);
const components = [
{ wave: "Q wave", def: "First negative deflection. Septal depolarization (left → right)." },
{ wave: "R wave", def: "First positive deflection. Free ventricular wall depolarization." },
{ wave: "S wave", def: "Negative deflection after R. Basal ventricular depolarization." },
];
components.forEach((c, i) => {
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 1.4 + i * 0.88, w: 4.5, h: 0.75, fill: { color: "0D2A5C" }, line: { color: C.accent, width: 1.2 } });
sl.addText(c.wave, { x: 0.65, y: 1.44 + i * 0.88, w: 1.1, h: 0.3, fontSize: 13, bold: true, color: C.gold, fontFace: "Calibri", margin: 0 });
sl.addText(c.def, { x: 0.65, y: 1.7 + i * 0.88, w: 4.2, h: 0.38, fontSize: 11.5, color: C.textBody, fontFace: "Calibri", margin: 0 });
});
subheading(sl, "Physiology", 1.02);
bodyText(sl, [
"Rapid spread via His-Purkinje system ensures near-simultaneous ventricular activation.",
"Conduction velocity in Purkinje system >> atrial conducting system.",
"Therefore QRS duration ≈ P wave duration despite much greater ventricular mass.",
"Atrial repolarization wave is buried within QRS — too small to see.",
], 0.5, 4.0, 5.5, 1.4);
// Right column – Normal values
subheading(sl, "Normal Values", 1.02);
const qrs = [
["QRS Duration", "< 0.12 s (< 3 small boxes)"],
["Q wave", "< 0.04 s duration; < 25% of R height"],
["Amplitude", "Lead-dependent; R/S ratio varies"],
["Axis", "-30° to +90° (normal)"],
];
qrs.forEach(([lbl, val], i) => {
labeledBox(sl, lbl, val, 5.5, 1.35 + i * 0.82);
});
sl.addShape(pres.ShapeType.rect, { x: 5.5, y: 4.65, w: 4.05, h: 0.7, fill: { color: "0D2A5C" }, line: { color: C.red, width: 1.5 } });
sl.addText("Wide QRS (≥ 0.12 s) = Bundle branch block, pre-excitation, or ventricular origin", { x: 5.6, y: 4.68, w: 3.85, h: 0.64, fontSize: 11, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0 });
footerSource(sl, "Guyton & Hall 14e p.142-143 · Costanzo Physiology 7e p.149 · Medical Physiology Boron & Boulpaep p.803");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 8 – ST SEGMENT & T WAVE
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "ST Segment & T Wave — Repolarization");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
// ST Segment
subheading(sl, "ST Segment", 1.02);
bodyText(sl, [
"From end of QRS (J point) to beginning of T wave.",
"Normally isoelectric — lies on baseline.",
"J point = junction of QRS end and ST start.",
"Represents early ventricular repolarization.",
], 0.5, 1.42, 4.5, 1.7);
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 3.12, w: 4.5, h: 0.82, fill: { color: "0D2A5C" }, line: { color: C.red, width: 1.5 } });
sl.addText([
{ text: "ST elevation: ", options: { bold: true, color: C.red } },
{ text: "Myocardial infarction (STEMI), pericarditis, Brugada syndrome.\n", options: { color: C.white } },
{ text: "ST depression: ", options: { bold: true, color: C.gold } },
{ text: "Ischaemia, posterior MI, digoxin effect.", options: { color: C.white } },
], { x: 0.65, y: 3.15, w: 4.2, h: 0.76, fontSize: 11, fontFace: "Calibri", valign: "middle" });
// T Wave
subheading(sl, "T Wave", 1.02);
bodyText(sl, [
"Represents ventricular REPOLARIZATION.",
"Normally upright (same direction as QRS) in most leads.",
"Ventricular muscle recovers 0.25–0.35 s after depolarization.",
"Much slower than depolarization — hence T wave is broad and rounded.",
"Atrial T wave (atrial repolarization) = hidden under QRS.",
], 5.2, 1.42, 4.4, 2.3);
// T wave normal values
accentBox(sl, 5.2, 3.75, 4.4, 0.55, "Normal T: Upright in I, II, V3-V6. Inverted in aVR (normal). Duration: 0.1-0.25 s", 11);
// QT interval
subheading(sl, "QT Interval", 4.35);
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 4.5, w: 9, h: 0.82, fill: { color: C.midBlue }, line: { color: "7B68EE", width: 1.5 } });
sl.addText([
{ text: "QT interval ", options: { bold: true, color: "7B68EE" } },
{ text: "= onset QRS → end T wave. Represents total ventricular electrical activity. Normal corrected QTc: 350–440 ms (males), 350–460 ms (females). Prolonged QTc → risk of Torsades de Pointes.", options: { color: C.white } }
], { x: 0.7, y: 4.53, w: 8.6, h: 0.76, fontSize: 12, fontFace: "Calibri", valign: "middle" });
footerSource(sl, "Goldman-Cecil Medicine 27e p.535 · Guyton & Hall 14e p.143 · Costanzo Physiology 7e p.149");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 9 – DEPOLARIZATION vs REPOLARIZATION
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "Depolarization vs Repolarization Waves");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "Key Principle from Guyton & Hall", 1.02);
const rows = [
{ label: "Depolarization", waves: "P wave, QRS complex", direction: "Positive (traveling toward electrode = upward deflection)", color: C.accent },
{ label: "Repolarization", waves: "T wave (U wave)", direction: "Negative if it followed same path as depolarization — but ventricles repolarize OUTSIDE→IN (opposite to depolarization), so T wave is POSITIVE in most leads", color: C.gold },
];
rows.forEach((r, i) => {
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 1.4 + i * 1.45, w: 9, h: 1.3, fill: { color: "0D2A5C" }, line: { color: r.color, width: 2 } });
sl.addText(r.label, { x: 0.65, y: 1.46 + i * 1.45, w: 2.2, h: 0.35, fontSize: 14, bold: true, color: r.color, fontFace: "Calibri", margin: 0 });
sl.addText("Waves: " + r.waves, { x: 0.65, y: 1.77 + i * 1.45, w: 4.5, h: 0.28, fontSize: 12, color: C.white, fontFace: "Calibri", margin: 0 });
sl.addText(r.direction, { x: 0.65, y: 2.02 + i * 1.45, w: 8.7, h: 0.6, fontSize: 11.5, color: C.textBody, fontFace: "Calibri", margin: 0 });
});
// ECG recording principle
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 4.25, w: 9, h: 1.0, fill: { color: C.midBlue }, line: { color: C.accent, width: 1.5 } });
sl.addText("Recording Principle", { x: 0.7, y: 4.28, w: 8.6, h: 0.3, fontSize: 13, bold: true, color: C.accent, fontFace: "Calibri", margin: 0 });
sl.addText([
{ text: "Current flows (and is detectable on ECG) ONLY when part of the myocardium is depolarized while another part remains polarized. ", options: { color: C.white } },
{ text: "When the whole heart is either fully polarized OR fully depolarized, the ECG returns to the isoelectric baseline.", options: { color: C.textBody, italic: true } }
], { x: 0.7, y: 4.55, w: 8.6, h: 0.65, fontSize: 12, fontFace: "Calibri" });
footerSource(sl, "Guyton & Hall 14e, Cardiac depolarization vs repolarization waves, p.142-143");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 10 – NORMAL ECG VALUES SUMMARY TABLE
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "Normal ECG Reference Values");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
// Table
const cols = [
{ label: "Parameter", w: 2.0, x: 0.4 },
{ label: "Normal Range", w: 2.5, x: 2.4 },
{ label: "Represents", w: 2.8, x: 4.9 },
{ label: "Clinical Significance", w: 2.3, x: 7.7 },
];
// Header row
cols.forEach(col => {
sl.addShape(pres.ShapeType.rect, { x: col.x, y: 0.95, w: col.w, h: 0.45, fill: { color: C.midBlue }, line: { color: C.accent, width: 1 } });
sl.addText(col.label, { x: col.x + 0.05, y: 0.97, w: col.w - 0.1, h: 0.41, fontSize: 11, bold: true, color: C.accent, fontFace: "Calibri", valign: "middle", margin: 0 });
});
const rows2 = [
["Heart Rate", "60–100 bpm", "SA node automaticity", "< 60 = bradycardia; > 100 = tachycardia"],
["P wave duration", "< 0.12 s", "Atrial depolarization", "> 0.12 s: left atrial enlargement"],
["P wave amplitude", "< 2.5 mm", "Atrial activation voltage", "> 2.5 mm in II: right atrial enlargement"],
["PR interval", "0.12–0.20 s", "AV node conduction", "> 0.20 s: 1st-degree AV block"],
["QRS duration", "< 0.12 s", "Ventricular depolarization", "≥ 0.12 s: bundle branch block"],
["QT interval (QTc)", "< 440 ms (M); < 460 ms (F)", "Ventricular repol.", "Prolonged → Torsades de Pointes risk"],
["ST segment", "Isoelectric (± 1 mm)", "Early ventricular repol.", "Elevation: STEMI; Depression: ischaemia"],
["T wave", "Upright in I, II, V3-V6", "Ventricular repolarization", "Peaked: hyperK; Inverted: ischaemia/LVH"],
];
rows2.forEach((row, ri) => {
const bg = ri % 2 === 0 ? "0D2A5C" : "091A3F";
const dataXs = [0.4, 2.4, 4.9, 7.7];
const dataWs = [2.0, 2.5, 2.8, 2.3];
row.forEach((cell, ci) => {
sl.addShape(pres.ShapeType.rect, { x: dataXs[ci], y: 1.4 + ri * 0.47, w: dataWs[ci], h: 0.45, fill: { color: bg }, line: { color: "1A3A6B", width: 0.5 } });
sl.addText(cell, { x: dataXs[ci] + 0.05, y: 1.42 + ri * 0.47, w: dataWs[ci] - 0.1, h: 0.41, fontSize: 10, color: C.textBody, fontFace: "Calibri", valign: "middle", margin: 0 });
});
});
footerSource(sl, "Medical Physiology Boron & Boulpaep p.732 · Costanzo Physiology 7e · Guyton & Hall 14e · Goldman-Cecil Medicine 27e");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 11 – ECG PAPER & GRID BASICS
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "Reading the ECG Paper");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "Standard ECG Paper Settings (25 mm/s, 10 mm/mV)", 1.02);
// Grid illustration using rectangles
const gx = 0.5, gy = 1.45, cs = 0.38; // cell size in inches (~10 mm = 0.38 in at scale)
// draw 5x5 large boxes each made of 5 small boxes
for (let row = 0; row < 5; row++) {
for (let col = 0; col < 5; col++) {
// small boxes (5 per large box)
for (let sr = 0; sr < 5; sr++) {
for (let sc = 0; sc < 5; sc++) {
sl.addShape(pres.ShapeType.rect, {
x: gx + (col * 5 + sc) * (cs / 5),
y: gy + (row * 5 + sr) * (cs / 5),
w: cs / 5, h: cs / 5,
fill: { type: "none" },
line: { color: "1E4070", width: 0.3 }
});
}
}
// large box border
sl.addShape(pres.ShapeType.rect, {
x: gx + col * cs, y: gy + row * cs, w: cs, h: cs,
fill: { type: "none" },
line: { color: "2A5FA0", width: 1.2 }
});
}
}
// Right column explanations
const gridFacts = [
{ title: "Small box", val: "1 mm × 1 mm", time: "0.04 s wide", volt: "0.1 mV tall", color: C.accent },
{ title: "Large box (5 small)", val: "5 mm × 5 mm", time: "0.20 s wide", volt: "0.5 mV tall", color: C.gold },
{ title: "Heart rate", val: "Count R-R interval", time: "1500 ÷ (small boxes in R-R)", volt: "or 300 ÷ (large boxes)", color: "7B68EE" },
];
gridFacts.forEach((f, i) => {
sl.addShape(pres.ShapeType.rect, { x: 2.65, y: 1.4 + i * 1.08, w: 6.9, h: 0.95, fill: { color: "0D2A5C" }, line: { color: f.color, width: 1.5 } });
sl.addText(f.title, { x: 2.8, y: 1.44 + i * 1.08, w: 2.5, h: 0.3, fontSize: 13, bold: true, color: f.color, fontFace: "Calibri", margin: 0 });
sl.addText(f.val, { x: 5.4, y: 1.44 + i * 1.08, w: 4.0, h: 0.3, fontSize: 12, color: C.white, fontFace: "Calibri", margin: 0 });
sl.addText(f.time + " | " + f.volt, { x: 2.8, y: 1.7 + i * 1.08, w: 6.6, h: 0.28, fontSize: 11, color: C.textBody, fontFace: "Calibri", margin: 0 });
});
// Calibration
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 4.72, w: 9, h: 0.65, fill: { color: C.midBlue }, line: { color: C.accent, width: 1 } });
sl.addText([
{ text: "Standard calibration: ", options: { bold: true, color: C.accent } },
{ text: "Paper speed 25 mm/s · Gain 10 mm/mV · Always check the calibration box at the start of the tracing before interpretation.", options: { color: C.white } }
], { x: 0.7, y: 4.74, w: 8.6, h: 0.6, fontSize: 12, fontFace: "Calibri", valign: "middle" });
footerSource(sl, "Standard ECG recording parameters — universal convention");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 12 – 12-LEAD ECG: LEADS OVERVIEW
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "The 12-Lead ECG — What Each Lead Sees");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "Lead Groups & Territory", 1.02);
const leadGroups = [
{ name: "Inferior leads", leads: "II, III, aVF", sees: "Inferior wall of left ventricle", artery: "RCA (usually)", color: C.green },
{ name: "Lateral leads", leads: "I, aVL, V5, V6", sees: "Lateral wall of left ventricle", artery: "LCx artery", color: C.accent },
{ name: "Anterior leads", leads: "V1–V4", sees: "Anterior wall of left ventricle", artery: "LAD artery", color: C.gold },
{ name: "Septal leads", leads: "V1, V2", sees: "Interventricular septum", artery: "LAD (septal perforators)", color: "7B68EE" },
{ name: "Right ventricle", leads: "V1, V3R, V4R", sees: "Right ventricular free wall", artery: "RCA", color: "FF7F50" },
];
leadGroups.forEach((g, i) => {
sl.addShape(pres.ShapeType.rect, { x: 0.4, y: 1.35 + i * 0.8, w: 9.2, h: 0.7, fill: { color: "0D2A5C" }, line: { color: g.color, width: 1.5 } });
sl.addText(g.name, { x: 0.55, y: 1.39 + i * 0.8, w: 2.0, h: 0.3, fontSize: 12, bold: true, color: g.color, fontFace: "Calibri", margin: 0 });
sl.addText("Leads: " + g.leads, { x: 0.55, y: 1.65 + i * 0.8, w: 2.0, h: 0.28, fontSize: 10.5, color: C.textBody, fontFace: "Calibri", margin: 0 });
sl.addText(g.sees, { x: 2.6, y: 1.39 + i * 0.8, w: 3.8, h: 0.58, fontSize: 11, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0 });
sl.addText("Supply: " + g.artery, { x: 6.5, y: 1.39 + i * 0.8, w: 3.0, h: 0.58, fontSize: 11, color: C.textBody, italic: true, fontFace: "Calibri", valign: "middle", margin: 0 });
});
sl.addShape(pres.ShapeType.rect, { x: 0.4, y: 5.35, w: 9.2, h: 0.0, fill: { type: "none" }, line: { color: "none" } });
footerSource(sl, "Standard 12-lead ECG interpretation — Einthoven's triangle & Wilson's unipolar leads");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 13 – U WAVE & J WAVE (SPECIAL WAVES)
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "Special ECG Waves: U Wave & J Wave");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
// U Wave
subheading(sl, "U Wave", 1.02);
bodyText(sl, [
"A small deflection AFTER the T wave, usually of the same polarity.",
"Origin debated: may represent late phases of ventricular repolarization (Purkinje system, papillary muscles).",
"Best seen in V2–V3.",
"Prominent U waves: hypokalemia, bradycardia.",
"Inverted U waves: left ventricular overload, ischaemia.",
], 0.5, 1.42, 4.5, 2.5);
// J Wave (Osborn)
subheading(sl, "J Wave (Osborn Wave)", 1.02);
sl.addShape(pres.ShapeType.rect, { x: 5.1, y: 1.35, w: 4.5, h: 3.3, fill: { color: "0D2A5C" }, line: { color: C.gold, width: 1.5 } });
sl.addText([
{ text: "Definition: ", options: { bold: true, color: C.gold } },
{ text: "Positive deflection on the QRS downstroke or at the J point.\n\n", options: { color: C.white } },
{ text: "Classic association: ", options: { bold: true, color: C.gold } },
{ text: "Hypothermia (core temp < 32°C). Amplitude correlates inversely with temperature.\n\n", options: { color: C.white } },
{ text: "Also seen in: ", options: { bold: true, color: C.gold } },
{ text: "Hypercalcaemia, brain injury, Brugada syndrome (variant).\n\n", options: { color: C.white } },
{ text: "The J wave breaks alphabetic convention of other ECG waves.", options: { color: C.textBody, italic: true } },
], { x: 5.2, y: 1.45, w: 4.3, h: 3.1, fontSize: 12, fontFace: "Calibri" });
// Bottom note
sl.addShape(pres.ShapeType.rect, { x: 0.5, y: 4.2, w: 4.5, h: 1.05, fill: { color: C.midBlue }, line: { color: C.accent, width: 1 } });
sl.addText([
{ text: "Summary of waves in order: ", options: { bold: true, color: C.accent } },
{ text: "\nP → Q → R → S → T → (U)\nEach named alphabetically (J wave is the exception)", options: { color: C.white } }
], { x: 0.65, y: 4.23, w: 4.2, h: 1.0, fontSize: 12, fontFace: "Calibri", valign: "middle" });
footerSource(sl, "Medical Physiology Boron & Boulpaep p.781 · Goldman-Cecil Medicine 27e p.535 · Guyton & Hall 14e");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 14 – SYSTEMATIC ECG INTERPRETATION APPROACH
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
heading(sl, "Systematic Approach to ECG Interpretation");
sl.addShape(pres.ShapeType.line, { x: 0.5, y: 0.88, w: 9, h: 0, line: { color: C.accent, width: 0.8 } });
subheading(sl, "A Step-by-Step Framework", 1.02);
const steps2 = [
{ n: "1", title: "Rate", detail: "Normal: 60-100 bpm. Method: 300 ÷ large boxes between R-R, or 1500 ÷ small boxes.", col: C.accent },
{ n: "2", title: "Rhythm", detail: "Is it regular or irregular? Is there a P wave before every QRS and a QRS after every P?", col: C.gold },
{ n: "3", title: "Axis", detail: "Normal: -30° to +90°. Check leads I and aVF: both positive = normal axis.", col: "7B68EE" },
{ n: "4", title: "P wave", detail: "Duration < 0.12 s, amplitude < 2.5 mm, upright in II, one per QRS.", col: C.green },
{ n: "5", title: "PR interval", detail: "0.12–0.20 s. Constant? Lengthening? Absent?", col: "FF7F50" },
{ n: "6", title: "QRS complex", detail: "Duration < 0.12 s. Morphology? Q waves? Voltage?", col: C.red },
{ n: "7", title: "ST segment & T wave", detail: "Isoelectric ST? T wave upright? Look for elevation, depression, inversion.", col: C.gold },
{ n: "8", title: "QT interval", detail: "QTc < 440 ms (M), < 460 ms (F). Prolonged QTc = arrhythmia risk.", col: C.accent },
];
steps2.forEach((s, i) => {
const col = i < 4 ? 0 : 1;
const row = i % 4;
const x = col === 0 ? 0.4 : 5.1;
const y = 1.35 + row * 0.98;
sl.addShape(pres.ShapeType.rect, { x, y, w: 4.55, h: 0.86, fill: { color: "0D2A5C" }, line: { color: s.col, width: 1.2 } });
sl.addText(s.n, { x: x + 0.05, y: y + 0.05, w: 0.38, h: 0.76, fontSize: 20, bold: true, color: s.col, fontFace: "Calibri", align: "center", valign: "middle", margin: 0 });
sl.addText(s.title, { x: x + 0.5, y: y + 0.06, w: 3.9, h: 0.3, fontSize: 13, bold: true, color: s.col, fontFace: "Calibri", margin: 0 });
sl.addText(s.detail, { x: x + 0.5, y: y + 0.34, w: 3.9, h: 0.46, fontSize: 10.5, color: C.textBody, fontFace: "Calibri", margin: 0 });
});
footerSource(sl, "Standard systematic ECG interpretation approach for medical students");
}
// ══════════════════════════════════════════════════════════════════
// SLIDE 15 – SUMMARY & KEY TAKEAWAYS
// ══════════════════════════════════════════════════════════════════
{
let sl = pres.addSlide();
darkSlide(sl);
sl.addShape(pres.ShapeType.line, { x: 0, y: 0.5, w: 10, h: 0, line: { color: C.accent, width: 1, dashType: "dash" } });
sl.addShape(pres.ShapeType.line, { x: 0, y: 5.1, w: 10, h: 0, line: { color: C.accent, width: 1, dashType: "dash" } });
sl.addText("KEY TAKEAWAYS", {
x: 0.5, y: 0.58, w: 9, h: 0.55,
fontSize: 30, bold: true, color: C.accent, charSpacing: 6,
fontFace: "Calibri", align: "center", margin: 0,
});
const takeaways = [
{ t: "P wave", d: "= Atrial depolarization (SA node → atria)" },
{ t: "PR interval", d: "= AV node conduction delay (0.12–0.20 s)" },
{ t: "QRS complex", d: "= Ventricular depolarization via His-Purkinje (< 0.12 s)" },
{ t: "ST segment", d: "= Early ventricular repolarization (normally isoelectric)" },
{ t: "T wave", d: "= Ventricular repolarization (normally upright)" },
{ t: "QT interval", d: "= Total ventricular electrical activity (QTc < 440/460 ms)" },
];
takeaways.forEach((tk, i) => {
const col = i < 3 ? 0 : 1;
const row = i % 3;
const x = col === 0 ? 0.4 : 5.1;
const y = 1.35 + row * 1.15;
sl.addShape(pres.ShapeType.rect, { x, y, w: 4.5, h: 1.0, fill: { color: "0D2A5C" }, line: { color: C.accent, width: 1 } });
sl.addText(tk.t, { x: x + 0.15, y: y + 0.08, w: 4.2, h: 0.35, fontSize: 16, bold: true, color: C.gold, fontFace: "Calibri", margin: 0 });
sl.addText(tk.d, { x: x + 0.15, y: y + 0.42, w: 4.2, h: 0.48, fontSize: 12.5, color: C.textBody, fontFace: "Calibri", margin: 0 });
});
sl.addText("The ECG traces the heart's electrical journey — from pacemaker to myocardium and back.", {
x: 0.5, y: 5.12, w: 9, h: 0.35, fontSize: 12, color: C.textBody, italic: true,
fontFace: "Calibri", align: "center", margin: 0,
});
}
// ─── WRITE FILE ───────────────────────────────────────────────────
pres.writeFile({ fileName: "/home/daytona/workspace/ecg-presentation/ECG_Basics_Waveforms.pptx" })
.then(() => console.log("SUCCESS: ECG_Basics_Waveforms.pptx created"))
.catch(e => { console.error("ERROR:", e); process.exit(1); });