Ecg explain Karo heart ke 20 diseases with ecg findings with photo
ECG findings 20 heart diseases with photos electrocardiogram patterns
https://tricog.com/common-ecg-patterns
ECG patterns STEMI atrial fibrillation heart block WPW pericarditis labeled diagram site:ecgwaves.com OR site:litfl.com
ECG STEMI inferior anterior lateral complete heart block LBBB ventricular fibrillation torsades images ecgwaves litfl
ECG atrial fibrillation flutter ventricular tachycardia fibrillation torsades hyperkalaemia pericarditis WPW images litfl ecgwaves
| Wave/Segment | Kya hota hai |
|---|---|
| P wave | Atria ka depolarization (Atrium ka contract karna) |
| PR interval | AV node se conduction ka time (Normal: 0.12-0.20 sec) |
| QRS complex | Ventricle ka depolarization (Normal: <0.12 sec) |
| ST segment | Ventricle depolarized rehta hai |
| T wave | Ventricle ka repolarization |
| QT interval | Total ventricular activity time |
| Leads | Area | Artery |
|---|---|---|
| II, III, aVF | Inferior wall | RCA (Right Coronary) |
| V1-V4 | Anterior wall | LAD (Left Anterior Descending) |
| I, aVL, V5-V6 | Lateral wall | LCx (Left Circumflex) |





| Stage | Changes |
|---|---|
| Stage 1 (Acute) | Diffuse ST elevation (saddle-shaped/concave up) + PR depression in most leads, PR elevation in aVR |
| Stage 2 | ST normalizes, T wave flattening |
| Stage 3 | T wave inversion (diffuse) |
| Stage 4 | ECG normalizes |
| K+ Level | ECG Changes |
|---|---|
| 5.5-6.5 | Peaked/tented T waves (narrow, symmetric, tall) |
| 6.5-7.5 | PR prolongation, wide QRS, P wave flattening |
| 7.5-8.5 | No P waves (sine wave pattern) |
| >8.5 | VF / cardiac arrest |
| # | Bimari | Sabse Khaas ECG Finding |
|---|---|---|
| 1 | STEMI | ST elevation + Q waves |
| 2 | NSTEMI/Unstable Angina | ST depression, T inversion |
| 3 | Atrial Fibrillation | No P waves, irregularly irregular |
| 4 | Atrial Flutter | Sawtooth flutter waves, 300 bpm |
| 5 | Ventricular Tachycardia | Wide complex, >100 bpm, AV dissociation |
| 6 | Ventricular Fibrillation | Chaotic waves, no QRS |
| 7 | Torsades de Pointes | Long QT + polymorphic VT |
| 8 | Complete Heart Block | P-QRS dissociation, bradycardia |
| 9 | 1st Degree AV Block | PR > 200ms |
| 10 | Wenckebach | Progressive PR lengthening + dropped beat |
| 11 | LBBB | Wide QRS, WiLLiaM, no Q in lateral |
| 12 | RBBB | Wide QRS, MaRRoW, rSR' in V1 |
| 13 | WPW | Short PR, delta wave, broad QRS |
| 14 | Pericarditis | Diffuse saddle ST elevation + PR depression |
| 15 | Cardiac Tamponade | Low voltage + electrical alternans |
| 16 | Hyperkalemia | Peaked T waves → sine wave |
| 17 | Hypokalemia | Prominent U waves, flat T |
| 18 | Pulmonary Embolism | S1Q3T3, sinus tach, RBBB |
| 19 | Brugada Syndrome | Coved ST elevation V1-V2 |
| 20 | LVH | High voltage, LV strain, SV1+RV5 >35mm |

"PQ ST QT" - Yeh segments ECG ka skeleton hain:
- P - Atrium
- Q - Ventricle start
- S-T - Ischemia/Infarction yahaan dikhti hai
- QT - Long = Torsades ka khatra
Please mark every abnormalities in ecg slides I m unable to understand
ls /home/daytona/workspace/ 2>/dev/null && echo "---" && ls /home/daytona/skills/pptx/
mkdir -p /home/daytona/workspace/ecg-slides/images /home/daytona/workspace/ecg-slides/annotated && echo "Directories created"
cd /home/daytona/workspace/ecg-slides/images && curl -sL "https://litfl.com/wp-content/uploads/2018/08/ECG-Inferior-AMI-STEMI-2.jpg" -o stemi_inferior.jpg && curl -sL "https://litfl.com/wp-content/uploads/2018/08/ECG-Inferior-AMI-STEMI-CHB-Complete-heart-block.jpg" -o complete_heart_block.jpg && curl -sL "https://litfl.com/wp-content/uploads/2018/08/ECG-ventricular-fibrillation-VF-rhythm-strips.jpg" -o vf.jpg && curl -sL "https://litfl.com/wp-content/uploads/2018/08/ECG-WPW-Atrial-fibrillation-2.jpg" -o wpw_af.jpg && curl -sL "https://www.ecgstampede.com/wp-content/uploads/2023/09/192-AFlutter2-1-1-scaled.jpg" -o atrial_flutter.jpg && ls -la
~/ecg-slides/annotate_ecg.py
#!/usr/bin/env python3
"""
ECG Annotation Script
Draws colored arrows, boxes, and labels on ECG images to mark abnormalities
"""
from PIL import Image, ImageDraw, ImageFont
import os
IMG_DIR = "/home/daytona/workspace/ecg-slides/images"
OUT_DIR = "/home/daytona/workspace/ecg-slides/annotated"
os.makedirs(OUT_DIR, exist_ok=True)
# ─── helper functions ───────────────────────────────────────────────────────
def load(name):
img = Image.open(os.path.join(IMG_DIR, name)).convert("RGB")
# Scale to max width 1400 for consistent annotation
w, h = img.size
if w > 1400:
ratio = 1400 / w
img = img.resize((1400, int(h * ratio)), Image.LANCZOS)
return img
def get_font(size=22):
try:
return ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", size)
except:
return ImageFont.load_default()
def get_font_regular(size=18):
try:
return ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", size)
except:
return ImageFont.load_default()
def draw_arrow(draw, start, end, color, width=3, head_size=14):
"""Draw arrow from start to end with arrowhead"""
import math
draw.line([start, end], fill=color, width=width)
# Arrowhead
dx = end[0] - start[0]
dy = end[1] - start[1]
length = math.sqrt(dx**2 + dy**2)
if length == 0:
return
dx, dy = dx/length, dy/length
# Two lines forming arrowhead
ax = end[0] - head_size*dx + head_size*0.5*dy
ay = end[1] - head_size*dy - head_size*0.5*dx
bx = end[0] - head_size*dx - head_size*0.5*dy
by = end[1] - head_size*dy + head_size*0.5*dx
draw.polygon([end, (ax,ay), (bx,by)], fill=color)
def draw_label(draw, pos, text, color, bg_color, font, padding=6):
"""Draw text label with background box"""
x, y = pos
bbox = draw.textbbox((x, y), text, font=font)
# Draw background
draw.rectangle([bbox[0]-padding, bbox[1]-padding,
bbox[2]+padding, bbox[3]+padding], fill=bg_color, outline=color, width=2)
draw.text((x, y), text, fill=color, font=font)
def draw_circle(draw, center, radius, color, width=3):
x, y = center
draw.ellipse([x-radius, y-radius, x+radius, y+radius], outline=color, width=width)
def draw_rect(draw, box, color, width=3):
draw.rectangle(box, outline=color, width=width)
def add_title_bar(img, title, subtitle="", bg="#1a1a2e", fg="#ffffff", accent="#e94560"):
"""Add a top title bar to the image"""
w, h = img.size
bar_h = 80 if subtitle else 55
new_img = Image.new("RGB", (w, h + bar_h), bg)
new_img.paste(img, (0, bar_h))
draw = ImageDraw.Draw(new_img)
# Title
font_title = get_font(28)
font_sub = get_font_regular(18)
draw.text((20, 8), title, fill=accent, font=font_title)
if subtitle:
draw.text((20, 42), subtitle, fill=fg, font=font_sub)
# Accent line
draw.line([(0, bar_h-2), (w, bar_h-2)], fill=accent, width=3)
return new_img
def add_legend(img, items, position="bottom"):
"""Add color legend to image"""
w, h = img.size
leg_h = 45
new_img = Image.new("RGB", (w, h + leg_h), "#0f0f1a")
if position == "bottom":
new_img.paste(img, (0, 0))
draw = ImageDraw.Draw(new_img)
font = get_font_regular(16)
x = 15
y = h + 10
for color, label in items:
draw.rectangle([x, y+2, x+25, y+22], fill=color)
draw.text((x+30, y), label, fill="#ffffff", font=font)
# estimate width
bbox = draw.textbbox((x+30, y), label, font=font)
x = bbox[2] + 25
return new_img
# ═══════════════════════════════════════════════════════════════════════════
# 1. INFERIOR STEMI
# ═══════════════════════════════════════════════════════════════════════════
def annotate_stemi():
img = load("stemi_inferior.jpg")
w, h = img.size
draw = ImageDraw.Draw(img)
font = get_font(20)
font_sm = get_font_regular(16)
RED = "#FF0000"
YELLOW = "#FFD700"
GREEN = "#00FF00"
CYAN = "#00FFFF"
WHITE = "#FFFFFF"
BG_RED = "#880000"
BG_YEL = "#665500"
BG_GRN = "#005500"
BG_CYN = "#005555"
# --- Lead II area (middle-left strip) - ST elevation mark
# Lead II is approximately y=260-360, x=0-350
# ST segments in lead II
draw_arrow(draw, (200, 180), (195, 290), RED, width=4)
draw_label(draw, (205, 155), "ST ELEVATION\n(Lead II)", RED, BG_RED, font)
# Lead III (bottom-left)
draw_arrow(draw, (200, 420), (195, 460), RED, width=4)
draw_label(draw, (205, 395), "ST ELEVATION\n(Lead III)", RED, BG_RED, font)
# aVF ST elevation (middle area)
draw_arrow(draw, (500, 200), (495, 290), RED, width=4)
draw_label(draw, (505, 170), "ST ELEVATION\naVF", RED, BG_RED, font)
# Reciprocal depression in aVL (top middle) - GREEN
draw_arrow(draw, (480, 110), (400, 95), GREEN, width=4)
draw_label(draw, (490, 90), "Reciprocal ST\nDepression aVL", GREEN, BG_GRN, font)
# Lead I - reciprocal depression
draw_arrow(draw, (100, 80), (100, 105), GREEN, width=4)
draw_label(draw, (110, 60), "Reciprocal Lead I", GREEN, BG_GRN, font)
# Q waves in inferior leads
draw_circle(draw, (165, 300), 18, YELLOW, width=3)
draw_label(draw, (190, 285), "Q wave", YELLOW, BG_YEL, font_sm)
draw_circle(draw, (155, 460), 18, YELLOW, width=3)
draw_label(draw, (180, 445), "Q wave", YELLOW, BG_YEL, font_sm)
# Hyperacute T waves
draw_arrow(draw, (750, 120), (700, 290), CYAN, width=3)
draw_label(draw, (760, 100), "Hyperacute\nT waves", CYAN, BG_CYN, font)
img = add_title_bar(img,
"❤️ INFERIOR STEMI (ST Elevation Myocardial Infarction)",
"RCA Occlusion | Leads II, III, aVF mein ST Elevation")
legend = [
(RED, "ST Elevation (Infarction)"),
(GREEN, "Reciprocal Depression"),
(YELLOW, "Pathological Q waves"),
(CYAN, "Hyperacute T waves"),
]
img = add_legend(img, legend)
img.save(os.path.join(OUT_DIR, "01_stemi_inferior.jpg"), quality=92)
print("✅ 1. STEMI annotated")
# ═══════════════════════════════════════════════════════════════════════════
# 2. COMPLETE HEART BLOCK + INFERIOR STEMI
# ═══════════════════════════════════════════════════════════════════════════
def annotate_chb():
img = load("complete_heart_block.jpg")
w, h = img.size
draw = ImageDraw.Draw(img)
font = get_font(20)
font_sm = get_font_regular(16)
RED = "#FF3333"
BLUE = "#3399FF"
ORANGE = "#FF8800"
PINK = "#FF66CC"
BG_RED = "#660000"
BG_BLU = "#003366"
BG_ORG = "#663300"
BG_PINK = "#660033"
WHITE = "#FFFFFF"
# P waves (atrial - independent, fast) - mark with blue circles along top strips
# In CHB, P waves march through at ~80 bpm independent of QRS
for px in [80, 195, 310, 430, 545, 660, 775, 890, 1005, 1120, 1250]:
if px < w:
draw_circle(draw, (px, 110), 12, BLUE, width=3)
draw_label(draw, (20, 60), "P waves (Atrial rate ~80 bpm)\n- Independent of QRS!", BLUE, BG_BLU, font)
draw_arrow(draw, (75, 58), (80, 95), BLUE, width=3)
# QRS complexes (ventricular escape - slow, wide)
for qx in [155, 430, 700, 970, 1250]:
if qx < w - 10:
draw_rect(draw, [qx-18, 70, qx+18, h-30], ORANGE, width=3)
draw_label(draw, (w//2 - 200, h-100), "Wide QRS Escape Beats\n(Ventricular rate ~35 bpm - SLOW!)", ORANGE, BG_ORG, font)
# AV Dissociation label
draw_label(draw, (w//2 - 180, 8), "AV DISSOCIATION - P waves & QRS COMPLETELY INDEPENDENT", RED, BG_RED, font)
# ST elevation in inferior leads (STEMI component)
draw_arrow(draw, (w-280, 160), (w-300, 220), RED, width=4)
draw_label(draw, (w-350, 135), "ST Elevation\n(Inferior STEMI)", RED, BG_RED, font)
# Bradycardia note
draw_label(draw, (20, h-90), "⚠ BRADYCARDIA - Heart Rate ~35 bpm - EMERGENCY: Pacemaker needed!", "#FF4444", "#220000", font_sm)
img = add_title_bar(img,
"🛑 3rd Degree AV Block (Complete Heart Block) + Inferior STEMI",
"P waves aur QRS bilkul alag! Koi conduction nahi AV node se")
legend = [
(BLUE, "P waves (Atrial - independent)"),
(ORANGE, "Wide QRS escape beats (Ventricular)"),
(RED, "ST Elevation (Inferior STEMI)"),
]
img = add_legend(img, legend)
img.save(os.path.join(OUT_DIR, "02_complete_heart_block.jpg"), quality=92)
print("✅ 2. Complete Heart Block annotated")
# ═══════════════════════════════════════════════════════════════════════════
# 3. VENTRICULAR FIBRILLATION
# ═══════════════════════════════════════════════════════════════════════════
def annotate_vf():
img = load("vf.jpg")
w, h = img.size
draw = ImageDraw.Draw(img)
font = get_font(20)
font_sm = get_font_regular(16)
RED = "#FF0000"
YELLOW = "#FFD700"
WHITE = "#FFFFFF"
BG_RED = "#660000"
BG_YEL = "#665500"
# Strip 1: VF chaotic waves - mark first strip
# y ~ 0 to h/5 (first strip)
strip_h = h // 5
# Box around chaotic region
draw_rect(draw, [0, 5, w-5, strip_h-5], RED, width=4)
draw_label(draw, (20, 15), "CHAOTIC WAVES - No P, No QRS, No T waves!", RED, BG_RED, font)
# Arrow to baseline
draw_arrow(draw, (w//2, strip_h*2+20), (w//2, strip_h*2+60), YELLOW, width=3)
draw_label(draw, (w//2 - 150, strip_h*2 - 10), "Irregular undulations - completely disorganized", YELLOW, BG_YEL, font_sm)
# "No QRS" labels on each strip
for i, strip_y in enumerate([strip_h//2, strip_h + strip_h//2, strip_h*2 + strip_h//2]):
if strip_y < h:
draw_label(draw, (w-250, strip_y-12), "No QRS Complex", "#FF6666", "#330000", font_sm)
# Shock markers visible in strip
draw_arrow(draw, (310, strip_h + 20), (345, strip_h + strip_h//2), "#00FF88", width=4)
draw_label(draw, (320, strip_h + 5), "Defibrillation shock", "#00FF88", "#003322", font_sm)
# Emergency box
big_font = get_font(26)
draw_rect(draw, [w-400, h-70, w-5, h-5], "#FF0000", width=5)
draw.rectangle([w-398, h-68, w-7, h-7], fill="#330000")
draw.text((w-390, h-60), "⚡ CARDIAC ARREST!\nDEFIBRILLATION NOW!", fill="#FF4444", font=font)
img = add_title_bar(img,
"💀 Ventricular Fibrillation (VF) - CARDIAC ARREST",
"Koi recognizable wave nahi - Immediate Defibrillation zaroori!")
legend = [
(RED, "Chaotic fibrillatory waves"),
(YELLOW, "No organized electrical activity"),
("#00FF88", "Defibrillation shock points"),
]
img = add_legend(img, legend)
img.save(os.path.join(OUT_DIR, "03_ventricular_fibrillation.jpg"), quality=92)
print("✅ 3. VF annotated")
# ═══════════════════════════════════════════════════════════════════════════
# 4. WPW + ATRIAL FIBRILLATION
# ═══════════════════════════════════════════════════════════════════════════
def annotate_wpw_af():
img = load("wpw_af.jpg")
w, h = img.size
draw = ImageDraw.Draw(img)
font = get_font(18)
font_sm = get_font_regular(15)
RED = "#FF2222"
ORANGE = "#FF9900"
CYAN = "#00FFFF"
YELLOW = "#FFDD00"
PINK = "#FF66FF"
BG_RED = "#550000"
BG_ORG = "#553300"
BG_CYN = "#004444"
BG_YEL = "#555500"
BG_PINK= "#440044"
# WPW + AF: wide irregular complex tachycardia
# Mark rate > 200 bpm
draw_label(draw, (20, 20), "Rate > 250 bpm - EXTREMELY DANGEROUS!", RED, BG_RED, font)
draw_arrow(draw, (300, 60), (350, 120), RED, width=4)
# Mark irregular wide QRS complexes
# Approximate QRS locations in top row
qrs_positions = [80, 150, 210, 280, 360, 440, 510, 580, 650, 720, 800, 870, 940, 1010, 1100, 1180, 1260, 1340]
for i, qx in enumerate(qrs_positions[:12]):
if qx < w - 30:
col = ORANGE if i % 2 == 0 else CYAN
draw_rect(draw, [qx-12, 80, qx+25, 200], col, width=2)
draw_label(draw, (20, 210), "Irregular WIDE QRS complexes\n(pre-excited via accessory pathway)", ORANGE, BG_ORG, font)
# No P waves
draw_label(draw, (w-420, 20), "NO P waves (AF + WPW)", YELLOW, BG_YEL, font)
# Varying RR intervals
draw_arrow(draw, (w//2, h//2 - 20), (w//2 - 80, h//2 + 30), PINK, width=3)
draw_arrow(draw, (w//2, h//2 - 20), (w//2 + 80, h//2 + 30), PINK, width=3)
draw_label(draw, (w//2 - 150, h//2 - 40), "Varying RR intervals\n(Irregularly irregular)", PINK, BG_PINK, font_sm)
# Delta waves in some complexes
draw_circle(draw, (210, 135), 15, CYAN, width=3)
draw_label(draw, (230, 120), "Delta wave\n(slurred upstroke)", CYAN, BG_CYN, font_sm)
# Warning box
draw_rect(draw, [5, h-80, w-5, h-5], "#FF0000", width=4)
draw.rectangle([7, h-78, w-7, h-7], fill="#330000")
draw.text((20, h-70), "⚠ DO NOT give AV nodal blockers (Digoxin/Verapamil/Adenosine) - Can cause VF!\n Treatment: IV Procainamide or DC Cardioversion", fill="#FF6666", font=font_sm)
img = add_title_bar(img,
"⚡ WPW Syndrome + Atrial Fibrillation - EMERGENCY",
"Pre-excited AF - Fast irregular wide complex - Rate >250 bpm")
legend = [
(RED, "Rate >250 bpm (life-threatening)"),
(ORANGE, "Wide pre-excited QRS"),
(CYAN, "Delta waves"),
(YELLOW, "No P waves (AF)"),
("#FF66FF", "Irregular RR intervals"),
]
img = add_legend(img, legend)
img.save(os.path.join(OUT_DIR, "04_wpw_af.jpg"), quality=92)
print("✅ 4. WPW+AF annotated")
# ═══════════════════════════════════════════════════════════════════════════
# 5. ATRIAL FLUTTER
# ═══════════════════════════════════════════════════════════════════════════
def annotate_aflutter():
img = load("atrial_flutter.jpg")
w, h = img.size
draw = ImageDraw.Draw(img)
font = get_font(20)
font_sm = get_font_regular(16)
RED = "#FF2222"
ORANGE = "#FF9900"
CYAN = "#00FFFF"
GREEN = "#44FF44"
BG_RED = "#550000"
BG_ORG = "#553300"
BG_CYN = "#004444"
BG_GRN = "#004400"
# The atrial flutter image shows sawtooth waves
# Lead II is typically where flutter waves are most visible
# Mark sawtooth pattern in inferior leads area
# The image is a 12-lead - Lead II ~y: h*0.3 to h*0.5 approximately
lead_II_y = int(h * 0.32)
lead_II_end = int(h * 0.48)
# Bracket the sawtooth region
draw_rect(draw, [0, lead_II_y, int(w*0.7), lead_II_end], ORANGE, width=3)
draw_label(draw, (20, lead_II_y - 35), "SAWTOOTH Flutter waves (F waves)\n~300 bpm atrial rate", ORANGE, BG_ORG, font)
draw_arrow(draw, (100, lead_II_y - 10), (100, lead_II_y + 20), ORANGE, width=4)
# Mark regular QRS complexes
# Typically every 2nd flutter wave conducts (2:1)
qrs_positions = [int(w*0.1), int(w*0.2), int(w*0.3), int(w*0.4),
int(w*0.5), int(w*0.6), int(w*0.7), int(w*0.8)]
for qx in qrs_positions[:6]:
if qx < w - 20:
draw_arrow(draw, (qx, int(h*0.22)), (qx, int(h*0.30)), GREEN, width=3)
draw_label(draw, (int(w*0.15), int(h*0.18)),
"Regular QRS complexes\n(2:1 conduction ~150 bpm)", GREEN, BG_GRN, font)
# Mark flutter waves between QRS
draw_arrow(draw, (int(w*0.25), int(h*0.52)), (int(w*0.22), int(h*0.42)), CYAN, width=3)
draw_label(draw, (int(w*0.26), int(h*0.53)), "Flutter waves between QRS\n(No isoelectric baseline)", CYAN, BG_CYN, font_sm)
# Atrial rate label
draw_label(draw, (int(w*0.7), int(h*0.1)), "Atrial Rate: ~300 bpm\nVentricular Rate: ~150 bpm\n(2:1 AV conduction)", RED, BG_RED, font)
img = add_title_bar(img,
"🔵 Atrial Flutter - Sawtooth Pattern",
"Lead II/III/aVF mein sawtooth flutter waves | 2:1 AV conduction")
legend = [
(ORANGE, "Sawtooth flutter waves (F waves) ~300 bpm"),
(GREEN, "Regular QRS complexes ~150 bpm"),
(CYAN, "No isoelectric baseline between waves"),
(RED, "2:1 AV conduction ratio"),
]
img = add_legend(img, legend)
img.save(os.path.join(OUT_DIR, "05_atrial_flutter.jpg"), quality=92)
print("✅ 5. Atrial Flutter annotated")
# ─── run all ───────────────────────────────────────────────────────────────
if __name__ == "__main__":
annotate_stemi()
annotate_chb()
annotate_vf()
annotate_wpw_af()
annotate_aflutter()
print("\n🎉 All ECG images annotated! Saved to:", OUT_DIR)
print("Files:", os.listdir(OUT_DIR))
cd /home/daytona/workspace/ecg-slides && python3 annotate_ecg.py 2>&1
~/ecg-slides/create_pptx.js
const pptxgen = require("pptxgenjs");
const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");
const OUT_DIR = "/home/daytona/workspace/ecg-slides/annotated";
const PPTX_OUT = "/home/daytona/workspace/ecg-slides/ECG_Heart_Diseases_Annotated.pptx";
// ─── fetch images as base64 ───────────────────────────────────────────────
function imgToBase64(filePath) {
const data = fs.readFileSync(filePath);
const ext = path.extname(filePath).replace(".", "").toLowerCase();
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png";
return `${mime};base64,${data.toString("base64")}`;
}
// ─── define slide data ────────────────────────────────────────────────────
const slides = [
// ── TITLE SLIDE ──
{
type: "title",
title: "ECG - 20 Heart Diseases",
subtitle: "Annotated ECG Slides with Marked Abnormalities\nHar abnormality clearly marked hai",
},
// ── SECTION: HOW TO READ ECG ──
{
type: "how_to",
title: "ECG Kaise Padhein? - Basic Waves",
bullets: [
"P wave = Atria contract karte hain (atrioventricular conduction)",
"PR interval = AV node delay (Normal: 0.12 - 0.20 sec)",
"QRS complex = Ventricle contract karte hain (Normal: <0.12 sec)",
"ST segment = Ventricular depolarization complete (Ischemia yahaan dikhti hai!)",
"T wave = Ventricle relax karta hai (Repolarization)",
"QT interval = Total ventricular cycle (Long QT = Torsades risk!)",
],
tableRows: [
["Wave", "Normal Value", "Abnormal agar..."],
["P wave", "0.08-0.10 sec", "Absent = AF; Wide/bifid = LAE"],
["PR interval", "0.12-0.20 sec", ">0.20 = 1st deg block"],
["QRS", "<0.12 sec", ">0.12 = BBB / VT"],
["QT", "<440 ms (men)", ">500 = Torsades risk"],
["ST segment", "Isoelectric", "Elevation = STEMI, Depression = Ischemia"],
],
},
// ── ANNOTATED REAL ECGs ──
{
type: "ecg_photo",
num: "01",
title: "1. INFERIOR STEMI - Real ECG (Annotated)",
imgFile: "01_stemi_inferior.jpg",
findings: [
"🔴 ST Elevation in II, III, aVF (Inferior leads) - RED arrows",
"🟢 Reciprocal ST Depression in I, aVL - GREEN arrows",
"🟡 Pathological Q waves - YELLOW circles",
"🔵 Hyperacute T waves (early sign) - CYAN arrows",
"Diagnosis: RCA occlusion → Inferior STEMI",
],
},
{
type: "ecg_photo",
num: "02",
title: "2. Complete Heart Block (3rd Degree AV Block) + STEMI",
imgFile: "02_complete_heart_block.jpg",
findings: [
"🔵 P waves - marked in BLUE circles (Atrial rate ~80 bpm)",
"🟠 Wide QRS escape beats - ORANGE boxes (Ventricular rate ~35 bpm)",
"🔴 ST Elevation (underlying inferior STEMI) - RED",
"Key finding: P waves aur QRS COMPLETELY INDEPENDENT hain",
"Treatment: Emergency Pacemaker + PCI",
],
},
{
type: "ecg_photo",
num: "03",
title: "3. Ventricular Fibrillation (VF) - CARDIAC ARREST",
imgFile: "03_ventricular_fibrillation.jpg",
findings: [
"🔴 CHAOTIC waves - No P, No QRS, No T - ALL marked in RED",
"No organized electrical activity",
"Irregular undulations - completely disorganized",
"⚡ Defibrillation shock points visible",
"EMERGENCY: Defibrillation 200J (Biphasic) + CPR",
],
},
{
type: "ecg_photo",
num: "04",
title: "4. WPW Syndrome + Atrial Fibrillation - EMERGENCY",
imgFile: "04_wpw_af.jpg",
findings: [
"🔴 Rate >250 bpm - EXTREMELY DANGEROUS",
"🟠 Wide pre-excited QRS complexes (orange boxes)",
"🔵 Delta waves visible (slurred upstroke) - CYAN circles",
"🟡 No P waves (Atrial Fibrillation)",
"🩷 Irregularly irregular RR intervals - PINK arrows",
"⚠ DO NOT give Digoxin/Verapamil/Adenosine → can cause VF!",
],
},
{
type: "ecg_photo",
num: "05",
title: "5. Atrial Flutter - Sawtooth Pattern",
imgFile: "05_atrial_flutter.jpg",
findings: [
"🟠 Sawtooth flutter waves (F waves) ~300 bpm - ORANGE box",
"🟢 Regular QRS complexes ~150 bpm - GREEN arrows",
"🔵 No isoelectric baseline between waves - CYAN",
"2:1 AV conduction ratio (every 2nd flutter wave conducts)",
"Lead II/III/aVF mein sawtooth most visible",
],
},
// ── TEXT-BASED SLIDES FOR REMAINING 15 DISEASES ──
{
type: "text_ecg",
num: "06",
title: "6. Atrial Fibrillation (AF)",
color: "#1565C0",
icon: "🫀",
findings: [
{ label: "No P waves", detail: "P waves completely absent - replaced by fibrillatory waves", color: "FF0000" },
{ label: "f-waves (fibrillatory)", detail: "Small irregular oscillations in baseline 300-600/min", color: "FF6600" },
{ label: "Irregularly irregular QRS", detail: "No pattern - completely random RR intervals", color: "FF0000" },
{ label: "QRS width", detail: "Usually normal (<0.12s) unless aberrant conduction", color: "006600" },
],
causes: "HTN, Valve disease, Thyrotoxicosis, CAD, Heart failure",
treatment: "Rate control (Beta-blocker/Digoxin) + Anticoagulation (Warfarin/NOAC)",
ecg_description: "Irregular wavy baseline + no P waves + irregular QRS complexes",
},
{
type: "text_ecg",
num: "07",
title: "7. Ventricular Tachycardia (VT)",
color: "#B71C1C",
icon: "⚡",
findings: [
{ label: "Wide QRS >0.12s", detail: "Broad bizarre QRS complexes (>3 small squares)", color: "FF0000" },
{ label: "Rate 100-250 bpm", detail: "Fast wide complex tachycardia", color: "FF0000" },
{ label: "AV Dissociation", detail: "P waves march through independently of QRS", color: "FF6600" },
{ label: "Fusion beats", detail: "Narrow QRS occasionally - diagnostic of VT", color: "0066FF" },
{ label: "Capture beats", detail: "Narrow QRS from conducted sinus beat - pathognomonic", color: "0066FF" },
{ label: "Concordance", detail: "All precordial QRS in same direction (all up or all down)", color: "FF6600" },
],
causes: "Ischemic heart disease (most common), Dilated CMP, Electrolyte imbalance",
treatment: "Pulseless VT: Defibrillation | Stable VT: Amiodarone IV",
ecg_description: "Wide complex tachycardia + AV dissociation + fusion/capture beats",
},
{
type: "text_ecg",
num: "08",
title: "8. Torsades de Pointes (TdP)",
color: "#4A148C",
icon: "🌀",
findings: [
{ label: "Long QT >500ms", detail: "QT interval prolonged BEFORE TdP episode", color: "FF0000" },
{ label: "Twisting QRS", detail: "QRS complexes twist around baseline - morphology changes", color: "FF0000" },
{ label: "Rate 200-250 bpm", detail: "Polymorphic wide complex tachycardia", color: "FF6600" },
{ label: "Short-long-short", detail: "Typical initiating sequence: short RR, long RR, then TdP", color: "0066FF" },
{ label: "Self-terminating", detail: "Often terminates spontaneously - can degenerate to VF", color: "006600" },
],
causes: "Hypokalemia, Hypomagnesemia, Drugs (Sotalol, Haloperidol, Erythromycin), Congenital Long QT",
treatment: "IV Magnesium Sulfate 2g | Stop offending drugs | Correct electrolytes",
ecg_description: "Sinusoidal twisting around baseline + changing QRS amplitude/axis",
},
{
type: "text_ecg",
num: "09",
title: "9. Left Bundle Branch Block (LBBB)",
color: "#0D47A1",
icon: "🔵",
findings: [
{ label: "Broad QRS >0.12s", detail: "Usually >0.14s (>3.5 small squares)", color: "FF0000" },
{ label: "WiLLiaM pattern", detail: "W shape in V1, M shape in V5/V6 (mnemonic)", color: "FF6600" },
{ label: "No septal Q waves", detail: "No Q waves in I, aVL, V5, V6 (abnormal!)", color: "FF0000" },
{ label: "ST-T discordance", detail: "ST/T wave opposite to main QRS direction - normal in LBBB", color: "0066FF" },
{ label: "Notched R waves", detail: "RSR' or RR' pattern in lateral leads", color: "006600" },
],
causes: "Hypertension (most common), IHD, Aortic stenosis, Dilated CMP",
treatment: "New LBBB + chest pain = STEMI equivalent → Use Sgarbossa criteria",
ecg_description: "Broad QRS + WiLLiaM + no Q in lateral + ST discordance",
},
{
type: "text_ecg",
num: "10",
title: "10. Right Bundle Branch Block (RBBB)",
color: "#1B5E20",
icon: "🟢",
findings: [
{ label: "Broad QRS >0.12s", detail: "Wide QRS complex", color: "FF0000" },
{ label: "MaRRoW pattern", detail: "M shape in V1 (rSR' = 'rabbit ears'), W in V5/V6", color: "FF6600" },
{ label: "rSR' in V1", detail: "Two R waves in V1 - most characteristic", color: "FF0000" },
{ label: "Wide S waves", detail: "Deep wide S waves in leads I, aVL, V5-V6", color: "0066FF" },
{ label: "ST-T discordance", detail: "T wave inversion in V1-V3 (appropriate discordance)", color: "006600" },
],
causes: "Normal variant, PE, RVH, Anterior MI, Myocarditis",
treatment: "New RBBB = investigate cause (especially PE!). Isolated RBBB = often benign",
ecg_description: "rSR' in V1 + wide S in I/V6 + ST-T discordance V1-V3",
},
{
type: "text_ecg",
num: "11",
title: "11. Wolff-Parkinson-White (WPW) Syndrome",
color: "#E65100",
icon: "⚡",
findings: [
{ label: "Short PR <0.12s", detail: "PR interval shortened (pre-excitation via accessory pathway)", color: "FF0000" },
{ label: "Delta wave", detail: "Slurred upstroke at beginning of QRS - pathognomonic!", color: "FF0000" },
{ label: "Broad QRS", detail: "QRS widened due to delta wave", color: "FF6600" },
{ label: "ST-T changes", detail: "Secondary repolarization abnormalities - pseudo-infarction", color: "0066FF" },
{ label: "Type A: R in V1", detail: "Left-sided pathway - dominant R in V1 (mimics RVH)", color: "006600" },
{ label: "Type B: S in V1", detail: "Right-sided pathway - dominant S in V1 (mimics LVH)", color: "006600" },
],
causes: "Congenital accessory pathway (Bundle of Kent)",
treatment: "Symptomatic: Radiofrequency ablation (curative) | AF+WPW: Procainamide",
ecg_description: "Short PR + delta wave + wide QRS = 'pre-excitation triad'",
},
{
type: "text_ecg",
num: "12",
title: "12. Pericarditis",
color: "#880E4F",
icon: "💛",
findings: [
{ label: "Diffuse ST elevation", detail: "Saddle-shaped (concave up) ST elevation in MULTIPLE leads", color: "FF0000" },
{ label: "PR depression", detail: "PR segment depressed in most leads - KEY FINDING vs STEMI!", color: "FF0000" },
{ label: "PR elevation in aVR", detail: "aVR shows PR elevation + ST depression", color: "FF6600" },
{ label: "Stage 1 (Acute)", detail: "Diffuse ST elevation + PR depression", color: "0066FF" },
{ label: "Stage 3", detail: "T wave inversion in multiple leads", color: "0066FF" },
{ label: "No reciprocal changes", detail: "Unlike STEMI - no specific reciprocal ST depression", color: "006600" },
],
causes: "Viral (Coxsackievirus), TB, Autoimmune, Post-MI (Dressler's), Uraemia",
treatment: "NSAIDs (Aspirin/Ibuprofen) + Colchicine | Rest for 3 months",
ecg_description: "Diffuse saddle-shape ST elev + PR depression (UNLIKE STEMI which is localized)",
},
{
type: "text_ecg",
num: "13",
title: "13. Cardiac Tamponade / Pericardial Effusion",
color: "#37474F",
icon: "💧",
findings: [
{ label: "Sinus tachycardia", detail: "Compensatory fast heart rate", color: "FF6600" },
{ label: "Low voltage QRS", detail: "<5mm in ALL limb leads, <10mm in ALL precordial leads", color: "FF0000" },
{ label: "Electrical alternans", detail: "QRS height alternates beat-to-beat - PATHOGNOMONIC!", color: "FF0000" },
{ label: "T wave flattening", detail: "Flat T waves in multiple leads", color: "0066FF" },
],
causes: "Malignancy, Viral pericarditis, TB, Trauma, Aortic dissection",
treatment: "EMERGENCY pericardiocentesis (drain the fluid!)",
ecg_description: "Low voltage + electrical alternans + tachycardia = TAMPONADE until proven otherwise",
},
{
type: "text_ecg",
num: "14",
title: "14. Pulmonary Embolism (PE)",
color: "#006064",
icon: "🫁",
findings: [
{ label: "Sinus tachycardia", detail: "Most common finding (44%) - non-specific but important", color: "FF0000" },
{ label: "S1Q3T3 pattern", detail: "Deep S in I + Q wave in III + T inversion in III", color: "FF0000" },
{ label: "New RBBB", detail: "Right heart strain causing RBBB", color: "FF6600" },
{ label: "T inversion V1-V4", detail: "Right ventricular strain pattern", color: "FF6600" },
{ label: "Right axis deviation", detail: "Axis shifts right due to RV overload", color: "0066FF" },
{ label: "Normal ECG", detail: "30% of PE cases have a normal ECG - don't exclude PE!", color: "006600" },
],
causes: "DVT, Immobility, Surgery, Malignancy, Pregnancy, OCP",
treatment: "Anticoagulation (LMWH → Warfarin/NOAC) | Massive PE: Thrombolysis",
ecg_description: "Sinus tach + S1Q3T3 + RBBB + RV strain = PE until proven otherwise",
},
{
type: "text_ecg",
num: "15",
title: "15. Hyperkalaemia (High Potassium)",
color: "#4E342E",
icon: "🔶",
findings: [
{ label: "Peaked T waves", detail: "Tall, narrow, symmetric 'tented' T waves - FIRST sign!", color: "FF0000" },
{ label: "PR prolongation", detail: "PR interval lengthens (K+ >6.5)", color: "FF6600" },
{ label: "QRS widening", detail: "Broad QRS complex (K+ >7.0)", color: "FF0000" },
{ label: "P wave flattening", detail: "P waves flatten and disappear (K+ >7.5)", color: "0066FF" },
{ label: "Sine wave", detail: "QRS merges with T wave - sine wave pattern (K+ >8.0)", color: "FF0000" },
{ label: "VF/Asystole", detail: "Terminal event - K+ >9.0", color: "FF0000" },
],
causes: "Renal failure (most common), ACE inhibitors, Potassium-sparing diuretics, Tissue necrosis",
treatment: "Calcium gluconate (stabilize membrane) + Insulin+Dextrose + Sodium bicarbonate + Dialysis",
ecg_description: "Progressive: Peaked T → Wide QRS → Sine wave → VF",
},
{
type: "text_ecg",
num: "16",
title: "16. Hypokalemia (Low Potassium)",
color: "#01579B",
icon: "🔷",
findings: [
{ label: "Prominent U waves", detail: "Hump after T wave (U wave >T wave amplitude) - HALLMARK!", color: "FF0000" },
{ label: "T wave flattening", detail: "T waves become flat or merge with U wave", color: "FF6600" },
{ label: "ST depression", detail: "Downsloping ST depression", color: "FF0000" },
{ label: "QT prolongation", detail: "Long QT (actually QU prolongation) - TdP risk!", color: "0066FF" },
{ label: "PR prolongation", detail: "Lengthened PR interval", color: "0066FF" },
],
causes: "Diuretics (thiazide/loop), Vomiting/diarrhea, Hyperaldosteronism, Poor intake",
treatment: "IV/oral KCl replacement | Correct Mg++ (cannot correct K+ without correcting Mg)",
ecg_description: "U waves + flat T waves + ST depression = Hypokalemia",
},
{
type: "text_ecg",
num: "17",
title: "17. Left Ventricular Hypertrophy (LVH)",
color: "#1A237E",
icon: "💙",
findings: [
{ label: "High voltage QRS", detail: "SV1 + RV5 or RV6 >35mm (Sokolow-Lyon criteria)", color: "FF0000" },
{ label: "R in aVL >11mm", detail: "Alternative LVH voltage criteria", color: "FF6600" },
{ label: "Left axis deviation", detail: "QRS axis more negative than -30°", color: "0066FF" },
{ label: "LV strain pattern", detail: "ST depression + T inversion in I, aVL, V5, V6", color: "FF0000" },
{ label: "Left atrial enlargement", detail: "Broad bifid P wave (P mitrale) in lead II", color: "0066FF" },
],
causes: "Hypertension (most common), Aortic stenosis, HCM, Athletic heart",
treatment: "Treat underlying cause (HTN control), ACE inhibitors cause regression",
ecg_description: "High voltage + LV strain + Left axis = LVH",
},
{
type: "text_ecg",
num: "18",
title: "18. Brugada Syndrome",
color: "#311B92",
icon: "⚡",
findings: [
{ label: "Type 1 (Diagnostic)", detail: "Coved ST elevation ≥2mm in V1-V2 + T wave inversion", color: "FF0000" },
{ label: "Coved morphology", detail: "ST elevation slopes down to inverted T - like a cobblestone roof", color: "FF0000" },
{ label: "Type 2 (Saddle-back)", detail: "Saddle-back ST pattern in V1-V2 (not diagnostic alone)", color: "FF6600" },
{ label: "Right precordial changes", detail: "Abnormalities in V1-V3 only", color: "0066FF" },
{ label: "Normal rest of ECG", detail: "Other leads appear normal", color: "006600" },
],
causes: "Autosomal dominant SCN5A mutation (Na+ channel) | Unmasked by: fever, Na-channel blockers",
treatment: "ICD (Implantable Cardioverter Defibrillator) - only proven therapy",
ecg_description: "Coved ST elevation V1-V2 = Type 1 Brugada = DIAGNOSTIC",
},
{
type: "text_ecg",
num: "19",
title: "19. 1st & 2nd Degree AV Block",
color: "#1B5E20",
icon: "⏱️",
findings: [
{ label: "1st Degree", detail: "PR interval >0.20s (>5 small squares) - every P followed by QRS", color: "0066FF" },
{ label: "Mobitz I (Wenckebach)", detail: "Progressive PR lengthening → dropped QRS (Grouped beating)", color: "FF6600" },
{ label: "Mobitz II", detail: "Constant PR + sudden dropped QRS (no warning) - DANGEROUS!", color: "FF0000" },
{ label: "2:1 Block", detail: "Every alternate P wave not conducted (can be Mobitz I or II)", color: "FF0000" },
{ label: "Grouped beating", detail: "Wenckebach shows clusters of beats with increasing PR", color: "006600" },
],
causes: "Inferior MI (1st/Wenckebach), Anterior MI (Mobitz II), Beta-blockers, Digoxin",
treatment: "1st degree: None | Wenckebach: Usually none | Mobitz II: Pacemaker!",
ecg_description: "1st: Long PR | Wenckebach: Grouped beats | Mobitz II: Sudden drop = pacemaker",
},
{
type: "text_ecg",
num: "20",
title: "20. NSTEMI / Unstable Angina",
color: "#B71C1C",
icon: "🔶",
findings: [
{ label: "ST depression", detail: "Horizontal or downsloping ST depression ≥0.5mm", color: "FF0000" },
{ label: "T wave inversion", detail: "Symmetric deep T wave inversion in affected territory", color: "FF0000" },
{ label: "NO ST elevation", detail: "Key differentiator from STEMI", color: "006600" },
{ label: "Wellens syndrome", detail: "Biphasic or deep T inversion V2-V3 = LAD proximal stenosis!", color: "FF6600" },
{ label: "De Winter T waves", detail: "Upsloping ST depression + tall T waves V1-V6 = LAD STEMI equivalent!", color: "FF6600" },
{ label: "Normal ECG possible", detail: "Up to 30% NSTEMI have normal ECG - troponin essential!", color: "0066FF" },
],
causes: "Atherosclerotic plaque rupture, Vasospasm, Demand ischemia",
treatment: "Aspirin + Heparin + Clopidogrel/Ticagrelor → Early angiography within 24h",
ecg_description: "ST depression + T inversion (no elevation) = NSTEMI/Unstable angina",
},
// ── SUMMARY SLIDE ──
{
type: "summary",
title: "Quick Summary - 20 Diseases at a Glance",
rows: [
["#", "Disease", "Key ECG Finding", "Emergency?"],
["1", "STEMI", "ST elevation + Q waves", "YES - PCI"],
["2", "NSTEMI", "ST depression, T inversion", "YES - Angiogram"],
["3", "AF", "No P waves, Irregular", "Rate control"],
["4", "Atrial Flutter", "Sawtooth waves 300 bpm", "Cardiovert"],
["5", "VT", "Wide complex, AV dissociation", "YES - Shock/Amio"],
["6", "VF", "Chaotic - no QRS", "YES - Defib NOW"],
["7", "Torsades", "Long QT + twisting QRS", "YES - Mg 2g IV"],
["8", "Complete Heart Block", "P-QRS dissociation", "YES - Pacemaker"],
["9", "1st Degree Block", "PR >200ms", "No"],
["10", "Wenckebach", "Progressive PR + dropped beat", "Usually No"],
["11", "LBBB", "Wide QRS, WiLLiaM", "If new: STEMI equiv"],
["12", "RBBB", "rSR' V1, wide S I/V6", "If new: think PE"],
["13", "WPW", "Short PR + delta wave", "If + AF: EMERGENCY"],
["14", "Pericarditis", "Diffuse ST + PR depression", "NSAIDs"],
["15", "Tamponade", "Low voltage + Alternans", "YES - Drain it!"],
["16", "Hyperkalemia", "Peaked T → sine wave", "YES - Ca gluconate"],
["17", "Hypokalemia", "U waves, flat T", "Replace K+"],
["18", "LVH", "High voltage + LV strain", "Treat HTN"],
["19", "PE", "S1Q3T3, tachycardia", "Anticoagulate"],
["20", "Brugada", "Coved ST V1-V2", "ICD"],
],
},
];
// ─── create presentation ──────────────────────────────────────────────────
const pres = new pptxgen();
pres.layout = "LAYOUT_WIDE"; // 13.3" × 7.5"
pres.title = "ECG - 20 Heart Diseases Annotated";
pres.author = "Orris Medical";
// Color palette
const C = {
bg_dark: "0D1B2A",
bg_mid: "1B2A3A",
bg_light: "1E3A5F",
accent: "E94560",
accent2: "F5A623",
white: "FFFFFF",
light: "B0C4DE",
green: "4CAF50",
red: "F44336",
blue: "2196F3",
yellow: "FFC107",
};
// ─── SLIDE RENDERERS ─────────────────────────────────────────────────────
function makeTitleSlide(data) {
const s = pres.addSlide();
// Background
s.background = { color: C.bg_dark };
// Red accent bar left
s.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 0.2, h: 7.5, fill: { color: C.accent } });
// Top accent line
s.addShape(pres.ShapeType.rect, { x: 0.2, y: 0, w: 13.1, h: 0.08, fill: { color: C.accent2 } });
// ECG wave decoration (simulated with text art)
s.addText("〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰", {
x: 0.3, y: 0.5, w: 12.8, h: 0.4, fontSize: 10, color: "334466", italic: true, align: "left"
});
s.addText("❤️", { x: 0.5, y: 1.5, w: 1.2, h: 1.2, fontSize: 64, align: "center" });
s.addText(data.title, {
x: 1.8, y: 1.3, w: 11.2, h: 1.5,
fontSize: 48, bold: true, color: C.white, align: "left",
});
s.addText(data.subtitle, {
x: 1.8, y: 2.9, w: 11, h: 1.2,
fontSize: 22, color: C.light, align: "left", italic: true,
});
// Bottom bar
s.addShape(pres.ShapeType.rect, { x: 0.2, y: 6.9, w: 13.1, h: 0.6, fill: { color: "111827" } });
s.addText("Orris Medical AI • ECG Interpretation Guide • 2026", {
x: 0.3, y: 6.95, w: 12.8, h: 0.4, fontSize: 14, color: "6B7280", align: "center"
});
}
function makeHowToSlide(data) {
const s = pres.addSlide();
s.background = { color: C.bg_dark };
s.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 13.3, h: 0.9, fill: { color: C.bg_light } });
s.addText(data.title, { x: 0.3, y: 0.1, w: 12.7, h: 0.7, fontSize: 28, bold: true, color: C.accent, align: "left" });
// Bullets (left side)
s.addText(
data.bullets.map(b => ({ text: "▶ " + b, options: { bullet: false, breakLine: true } })),
{ x: 0.3, y: 1.0, w: 6.5, h: 5.0, fontSize: 15, color: C.white, valign: "top" }
);
// Table (right side)
const tableData = data.tableRows.map((row, i) => row.map(cell => ({
text: cell,
options: {
bold: i === 0,
color: i === 0 ? C.accent : C.white,
fill: { color: i === 0 ? C.bg_mid : (i % 2 === 0 ? "1a2a3a" : C.bg_dark) },
fontSize: i === 0 ? 13 : 12,
}
})));
s.addTable(tableData, { x: 7.1, y: 1.0, w: 6.0, h: 5.0, border: { type: "solid", color: "334466" } });
}
function makeEcgPhotoSlide(data) {
const imgPath = path.join(OUT_DIR, data.imgFile);
if (!fs.existsSync(imgPath)) {
console.warn("⚠ Image not found:", imgPath);
return;
}
const imgData = imgToBase64(imgPath);
const s = pres.addSlide();
s.background = { color: "0a0a0f" };
// Top title bar
s.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 13.3, h: 0.75, fill: { color: C.bg_light } });
s.addShape(pres.ShapeType.rect, { x: 0, y: 0.75, w: 13.3, h: 0.05, fill: { color: C.accent } });
s.addText(data.title, { x: 0.2, y: 0.07, w: 12.9, h: 0.62, fontSize: 22, bold: true, color: C.white });
// ECG image (left - large)
s.addImage({ data: imgData, x: 0.1, y: 0.9, w: 8.8, h: 5.5 });
// Findings panel (right)
s.addShape(pres.ShapeType.rect, { x: 9.1, y: 0.9, w: 4.1, h: 5.5, fill: { color: C.bg_mid }, line: { color: "334466", width: 1 } });
s.addText("📋 ECG Findings:", {
x: 9.2, y: 0.95, w: 4.0, h: 0.4, fontSize: 16, bold: true, color: C.accent2
});
s.addText(
data.findings.map(f => ({ text: f, options: { breakLine: true } })),
{ x: 9.2, y: 1.4, w: 3.9, h: 4.8, fontSize: 14, color: C.white, valign: "top" }
);
}
function makeTextEcgSlide(data) {
const s = pres.addSlide();
s.background = { color: C.bg_dark };
// Title bar
s.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 13.3, h: 0.85, fill: { color: data.color || C.bg_light } });
s.addText(`${data.icon} ${data.title}`, {
x: 0.2, y: 0.1, w: 12.9, h: 0.65, fontSize: 26, bold: true, color: C.white, align: "left"
});
// ECG description box
s.addShape(pres.ShapeType.rect, { x: 0.2, y: 0.95, w: 13.0, h: 0.55,
fill: { color: "1a0a0a" }, line: { color: C.accent, width: 2 } });
s.addText(`🔑 ECG Pattern: ${data.ecg_description}`, {
x: 0.35, y: 0.97, w: 12.8, h: 0.5, fontSize: 15, bold: true, color: C.accent2
});
// Findings (two columns)
const half = Math.ceil(data.findings.length / 2);
const col1 = data.findings.slice(0, half);
const col2 = data.findings.slice(half);
// Column headers
s.addText("ECG ABNORMALITIES - MARKED", {
x: 0.2, y: 1.6, w: 6.4, h: 0.35, fontSize: 14, bold: true, color: C.accent,
fill: { color: C.bg_mid }
});
s.addText("CAUSES & TREATMENT", {
x: 6.9, y: 1.6, w: 6.2, h: 0.35, fontSize: 14, bold: true, color: C.accent,
fill: { color: C.bg_mid }
});
// Findings column 1
col1.forEach((f, i) => {
const yPos = 2.05 + i * 0.82;
s.addShape(pres.ShapeType.rect, { x: 0.2, y: yPos, w: 6.4, h: 0.75,
fill: { color: i % 2 === 0 ? "1a2a3a" : "141e2a" }, line: { color: "334466", width: 1 } });
s.addShape(pres.ShapeType.rect, { x: 0.2, y: yPos, w: 0.12, h: 0.75,
fill: { color: f.color || C.accent } });
s.addText([
{ text: f.label + "\n", options: { bold: true, color: f.color || C.accent, fontSize: 14 } },
{ text: f.detail, options: { color: C.light, fontSize: 12 } }
], { x: 0.4, y: yPos + 0.06, w: 6.0, h: 0.65, valign: "top" });
});
// Findings column 2 (right)
col2.forEach((f, i) => {
const yPos = 2.05 + i * 0.82;
s.addShape(pres.ShapeType.rect, { x: 6.9, y: yPos, w: 6.2, h: 0.75,
fill: { color: i % 2 === 0 ? "1a2a3a" : "141e2a" }, line: { color: "334466", width: 1 } });
s.addShape(pres.ShapeType.rect, { x: 6.9, y: yPos, w: 0.12, h: 0.75,
fill: { color: f.color || C.accent } });
s.addText([
{ text: f.label + "\n", options: { bold: true, color: f.color || C.accent, fontSize: 14 } },
{ text: f.detail, options: { color: C.light, fontSize: 12 } }
], { x: 7.1, y: yPos + 0.06, w: 5.8, h: 0.65, valign: "top" });
});
// Bottom causes/treatment panel
const panelY = 2.05 + half * 0.82 + 0.1;
if (panelY < 7.0) {
s.addShape(pres.ShapeType.rect, { x: 6.9, y: panelY, w: 6.2, h: 0.6,
fill: { color: "001a00" }, line: { color: "2d6a2d", width: 1 } });
s.addText([
{ text: "🔎 Causes: ", options: { bold: true, color: "#66FF66", fontSize: 12 } },
{ text: data.causes, options: { color: C.light, fontSize: 11 } }
], { x: 7.0, y: panelY + 0.05, w: 6.0, h: 0.25 });
s.addShape(pres.ShapeType.rect, { x: 6.9, y: panelY + 0.28, w: 6.2, h: 0.3,
fill: { color: "1a0000" }, line: { color: "6a2d2d", width: 1 } });
s.addText([
{ text: "💊 Rx: ", options: { bold: true, color: "#FF8888", fontSize: 12 } },
{ text: data.treatment, options: { color: C.light, fontSize: 11 } }
], { x: 7.0, y: panelY + 0.3, w: 6.0, h: 0.25 });
}
}
function makeSummarySlide(data) {
const s = pres.addSlide();
s.background = { color: C.bg_dark };
s.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 13.3, h: 0.7, fill: { color: C.accent } });
s.addText(data.title, { x: 0.2, y: 0.08, w: 12.9, h: 0.55, fontSize: 24, bold: true, color: C.white });
const tableData = data.rows.map((row, i) => {
const isHeader = i === 0;
return row.map((cell, ci) => {
let fillColor = isHeader ? "1a1a2e" : (i % 2 === 0 ? "141e2a" : "1a2a3a");
// Emergency column color
if (!isHeader && ci === 3) {
if (cell.includes("YES")) fillColor = "2a0a0a";
else if (cell.includes("No")) fillColor = "0a1a0a";
}
return {
text: cell,
options: {
bold: isHeader || ci === 1,
color: isHeader ? C.accent : (ci === 3 && cell.includes("YES") ? "FF6666" : C.white),
fontSize: isHeader ? 13 : 11,
fill: { color: fillColor },
align: ci === 0 ? "center" : "left",
}
};
});
});
s.addTable(tableData, {
x: 0.1, y: 0.8, w: 13.1, h: 6.6,
colW: [0.4, 1.8, 3.6, 3.0, 4.3],
border: { type: "solid", color: "2a3a4a" }
});
}
// ─── render all slides ────────────────────────────────────────────────────
for (const slide of slides) {
switch (slide.type) {
case "title": makeTitleSlide(slide); break;
case "how_to": makeHowToSlide(slide); break;
case "ecg_photo": makeEcgPhotoSlide(slide); break;
case "text_ecg": makeTextEcgSlide(slide); break;
case "summary": makeSummarySlide(slide); break;
}
}
pres.writeFile({ fileName: PPTX_OUT })
.then(() => console.log("✅ PPTX saved:", PPTX_OUT))
.catch(e => { console.error("❌ Error:", e); process.exit(1); });
cd /home/daytona/workspace/ecg-slides && node create_pptx.js 2>&1
ls -lh /home/daytona/workspace/ecg-slides/ECG_Heart_Diseases_Annotated.pptx && ls -lh /home/daytona/workspace/ecg-slides/annotated/
ECG Heart Diseases Annotated
Presentation · PPTX
| Slides | Content |
|---|---|
| Slide 1 | Title slide |
| Slide 2 | ECG basics (P, QRS, T table) |
| Slides 3-7 | Real annotated ECG photos (STEMI, CHB, VF, WPW+AF, Flutter) |
| Slides 8-26 | 15 diseases - detailed findings, causes, treatment panels |
| Slide 27 | Quick summary table (all 20 diseases) |