Make a full notes about ECG to a 3rd year medical student

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Loading Image
Loading Image
Reading File
Loading Image

Finish it

I have all the content I need from the textbooks. Here are the complete ECG notes:

ECG (Electrocardiogram) - Complete Notes for 3rd Year Medical Students


1. INTRODUCTION

The ECG is a non-invasive recording of the electrical activity of the heart from the body surface. It was introduced by Einthoven in the early 1900s and remains one of the most important tools in clinical medicine. It provides direct measurement of:
  • Heart rate
  • Heart rhythm
  • Conduction pathways
  • Ischemia / infarction patterns
  • Hypertrophy and metabolic disturbances
"Electrocardiography allows simultaneous recording of myocardial activation from multiple vantage points on the body's surface, thereby permitting analysis of electrical activation in different myocardial regions." - Goldman-Cecil Medicine

2. THE CARDIAC CONDUCTION SYSTEM

Understanding the ECG starts with understanding how electrical impulses travel through the heart.
Cardiac conduction system showing SA node, AV node, Bundle of His, bundle branches, and Purkinje fibers
Cardiac conduction system - Goldman-Cecil Medicine
The sequence of normal electrical activation:
  1. SA node - located in the high lateral epicardial right atrium near the superior vena cava. Spontaneously depolarizes at the highest rate - it is the dominant pacemaker (60-100 bpm intrinsic rate).
  2. Atria - the wave front spreads through both atria. The Bachmann bundle speeds conduction to the left atrium. This produces the P wave.
  3. AV node - the only electrical connection between atria and ventricles (the AV rings are electrically insulated). Physiologic delay occurs here. This produces the PR interval.
  4. Bundle of His - exits the AV node; capable of rapid conduction.
  5. Bundle branches - the His bundle bifurcates into the right bundle branch and the left bundle branch. The left further divides into the left anterior fascicle and left posterior fascicle.
  6. Purkinje system - distal ramifications that rapidly deliver current to ventricular myocytes.
  7. Ventricular myocardium - depolarization produces the QRS complex; repolarization produces the T wave.

3. ECG PAPER AND TECHNICAL STANDARDS

Normal ECG waveform with labeled intervals, segments, and grid measurements
Normal ECG waveform with all intervals labeled - Goldman-Cecil Medicine
ParameterValue
Paper speed25 mm/sec
Small box (1 mm)0.04 sec horizontally; 0.1 mV vertically
Large box (5 mm)0.2 sec horizontally; 0.5 mV vertically
Standard calibration10 mm = 1 mV
Recording duration10 seconds (standard ECG)
A standard 12-lead ECG records 4 groups of leads simultaneously: (I, II, III), (aVR, aVL, aVF), (V1, V2, V3), (V4, V5, V6) - each for 2.5 seconds. A rhythm strip runs below for the full 10 seconds.

4. THE ECG LEADS

Limb Leads (Frontal Plane)

LeadPositive ElectrodeViews
Lead ILeft armLateral wall
Lead IILeft legInferior wall
Lead IIILeft legInferior wall
aVRRight armCavity (inverted)
aVLLeft armLateral wall
aVFLeft legInferior wall

Precordial Leads (Horizontal Plane)

LeadPositionViews
V14th ICS, right sternal borderSeptal / RV
V24th ICS, left sternal borderSeptal
V3Between V2 and V4Anterior
V45th ICS, midclavicular lineAnterior
V5Anterior axillary line (same level as V4)Lateral
V6Midaxillary line (same level as V4)Lateral
Key concept: Each lead looks at the heart from a different angle. A positive deflection means the electrical wavefront is traveling toward the positive electrode.

5. ECG WAVEFORMS - WHAT EACH REPRESENTS

Cardiac cycle diagram showing the relationship between ECG, ventricular pressure, aortic flow, and ventricular volume
Cardiac cycle correlated with the ECG - Miller's Anesthesia

P Wave

  • Represents: Atrial depolarization (both right and left atria)
  • Normal duration: < 0.12 sec (< 3 small boxes)
  • Normal amplitude: < 2.5 mm in limb leads; < 1.5 mm in precordial leads
  • Morphology: Upright in leads I, II, aVF, V4-V6; inverted in aVR
  • Abnormalities:
    • Broad/bifid P (P mitrale) → Left atrial enlargement
    • Tall/peaked P (P pulmonale, >2.5 mm) → Right atrial enlargement
    • Absent P waves → AF, junctional rhythm, SA block

PR Interval

  • Represents: Time from start of atrial depolarization to start of ventricular depolarization (includes AV nodal delay)
  • Normal: 0.09 - 0.20 sec (90-200 msec)
  • Prolonged (>0.20 sec): 1st degree AV block (delay usually in AV node)
  • Short (<0.09 sec): Ventricular pre-excitation (WPW syndrome), junctional rhythm, or enhanced AV nodal conduction

QRS Complex

  • Represents: Ventricular depolarization
  • Normal duration: 0.075 - 0.11 sec (75-110 msec)
  • Nomenclature:
    • Capital letters (Q, R, S) = amplitude ≥ 5 mm (0.5 mV)
    • Lowercase letters (q, r, s) = amplitude < 5 mm
    • Q/q = initial negative deflection
    • R/r = positive deflection
    • S/s = negative deflection after a positive deflection
    • QS = entirely negative deflection
    • R' = second positive deflection (after S wave)
  • Prolonged QRS (>0.11 sec): Bundle branch block, ventricular rhythm, pre-excitation

ST Segment

  • Represents: Early ventricular repolarization (plateau phase of action potential)
  • Normal: Isoelectric (at baseline)
  • J point: Junction between the end of QRS and beginning of ST segment
  • Abnormalities:
    • ST elevation → Acute STEMI, pericarditis, Prinzmetal angina, LBBB, LVH
    • ST depression → NSTEMI/UA, subendocardial ischemia, digoxin effect, hypokalemia

T Wave

  • Represents: Ventricular repolarization
  • Normal: Upright in I, II, V3-V6; inverted in aVR (and often V1)
  • Amplitude: < 10 mm precordial; < 5 mm limb leads
  • Abnormalities:
    • Tall, peaked T waves → Hyperkalemia (early), STEMI (hyperacute T waves)
    • T wave inversion → Ischemia, ventricular hypertrophy strain pattern, RBBB, LBBB, CNS events

QT Interval

  • Represents: Total ventricular depolarization + repolarization
  • Measured: QRS onset to end of T wave; in leads II, V5, V6
  • Must be rate-corrected: Use Bazett's formula: QTc = QT / √RR (RR in seconds)
  • Normal QTc:
    • Males: 390-450 msec
    • Females: 390-460 msec
  • Prolonged QTc: Risk of Torsades de Pointes (TdP) and sudden cardiac death
    • Causes: Drugs (antiarrhythmics, antipsychotics, antibiotics), hypokalemia, hypomagnesemia, hypocalcemia, congenital long QT syndrome
  • Short QTc (<350 msec): Hypercalcemia, digoxin, congenital short QT syndrome

U Wave

  • Small deflection after the T wave; best seen in V2-V3
  • Represents: Repolarization of Purkinje fibers / interventricular septum (debated)
  • Prominent U waves: Hypokalemia, bradycardia, hypothermia
  • Note: Prominent U waves can complicate QTc measurement

J Wave (Osborn Wave)

  • Positive deflection at the J point (QRS downstroke)
  • Seen in: Hypothermia (most common), hypercalcemia, brain injury
  • May indicate risk of idiopathic ventricular fibrillation

6. HEART RATE CALCULATION

Method 1 (Precise) - R-R interval:
HR = 60 / R-R interval (in seconds) = 60,000 / R-R interval (in msec)
Method 2 (Quick) - Large box counting: Count large boxes between two consecutive R waves, then use:
300 - 150 - 100 - 75 - 60 - 50 (for 1, 2, 3, 4, 5, 6 large boxes) Formula: HR = 300 / (number of large boxes)
Method 3 (Irregular rhythm): Count number of QRS complexes in 10-second strip × 6
RateInterpretation
< 50 bpmBradycardia
50-100 bpmNormal
> 100 bpmTachycardia

7. NORMAL INTERVAL SUMMARY TABLE

Interval/WaveNormal ValueClinical Significance if Abnormal
HR50-100 bpmBrady/tachycardia
P wave duration< 120 msecAtrial enlargement if broad
PR interval90-200 msecAV block if long; WPW if short
QRS duration75-110 msecBBB if > 120 msec
QTc (male)390-450 msecTdP risk if prolonged
QTc (female)390-460 msecTdP risk if prolonged
QRS axis-30° to +90°LAD / RAD if deviated

8. QRS AXIS

The electrical axis is the overall direction of ventricular depolarization in the frontal plane.
Normal axis: -30° to +90°

Quick method using Leads I and aVF:

Lead ILead aVFAxis
PositivePositiveNormal (-30° to +90°)
PositiveNegativeLeft axis deviation (LAD)
NegativePositiveRight axis deviation (RAD)
NegativeNegativeExtreme RAD ("Northwest axis")
More precise: The axis points toward the lead where the QRS is most positive (or away from where it is most negative). The axis is perpendicular to the lead where the QRS is isoelectric (equal positive/negative deflection).

Causes of Axis Deviation:

Left Axis Deviation (LAD, more negative than -30°):
  • Left anterior fascicular block (most common)
  • Left ventricular hypertrophy
  • Inferior STEMI
  • WPW (right-sided accessory pathway)
Right Axis Deviation (RAD, more positive than +90°):
  • Right ventricular hypertrophy
  • Left posterior fascicular block
  • Pulmonary embolism / cor pulmonale
  • WPW (left-sided accessory pathway)
  • Normal in children and tall thin adults

9. SYSTEMATIC APPROACH TO ECG INTERPRETATION

Use a consistent method every time. A reliable mnemonic is:
"Rate, Rhythm, Axis, Intervals, Hypertrophy, Ischemia/Infarction"

Step-by-Step:

  1. Rate - calculate using large-box method
  2. Rhythm - regular or irregular? Is there a P for every QRS? Is there a QRS for every P?
  3. P wave - present, morphology, axis (upright in I and II = sinus origin)
  4. PR interval - normal, prolonged, or short?
  5. QRS complex - duration, morphology, pathological Q waves?
  6. QRS axis - using leads I and aVF
  7. ST segment - elevation or depression?
  8. T waves - normal, inverted, tall/peaked?
  9. QT interval - calculate QTc
  10. Overall interpretation - put it all together

10. NORMAL SINUS RHYTHM (NSR) - Criteria

  • Regular rhythm
  • Rate 60-100 bpm
  • P wave upright in I, II, aVF; inverted in aVR
  • Every P followed by QRS; every QRS preceded by P
  • PR interval 120-200 msec
  • QRS < 120 msec
  • Normal axis

11. COMMON ARRHYTHMIAS

Sinus Arrhythmia

  • Subtle variation in heart rate with respiration
  • Inspiration → faster rate; expiration → slower rate
  • Normal variant - no treatment required

Sinus Tachycardia

  • Rate > 100 bpm; otherwise normal ECG
  • Causes: exercise, anxiety, fever, pain, anemia, hypovolemia, hyperthyroidism
  • Treat the underlying cause

Sinus Bradycardia

  • Rate < 60 bpm; otherwise normal ECG
  • Causes: athletes, sleep, hypothyroidism, sick sinus syndrome, medications (beta-blockers)

Atrial Fibrillation (AF)

  • Irregularly irregular rhythm
  • No distinct P waves - replaced by chaotic fibrillatory baseline
  • Narrow QRS (unless aberrant conduction)
  • Rate: variable (ventricular rate depends on AV node conduction)

Atrial Flutter

  • Regular sawtooth flutter waves at ~300 bpm (P waves)
  • Usually 2:1 AV block → ventricular rate ~150 bpm
  • Sawtooth most visible in leads II, III, aVF

Supraventricular Tachycardia (SVT)

  • Regular narrow-complex tachycardia, rate 150-250 bpm
  • P waves may be hidden in QRS or just after QRS
  • Includes AVNRT, AVRT

Ventricular Tachycardia (VT)

  • ≥3 consecutive wide QRS complexes at rate > 100 bpm
  • AV dissociation (independent P waves), fusion beats, capture beats
  • Emergency - risk of degeneration to VF

Ventricular Fibrillation (VF)

  • Chaotic, irregular wide complexes - no discernible QRS/T
  • No cardiac output - cardiac arrest
  • Treat with immediate defibrillation

12. AV BLOCKS

1st Degree AV Block

  • PR interval > 200 msec (one large box)
  • All P waves conduct to ventricles
  • Usually benign; no treatment needed

2nd Degree AV Block - Mobitz Type I (Wenckebach)

  • Progressive PR prolongation until a P wave is not conducted (dropped QRS)
  • Then cycle repeats
  • Site of block: usually AV node
  • Usually benign

2nd Degree AV Block - Mobitz Type II

  • Fixed PR interval with sudden dropped QRS (no progressive lengthening)
  • Site of block: His-Purkinje system (below the AV node)
  • More serious - can progress to complete heart block
  • May need pacemaker

3rd Degree (Complete) AV Block

  • Complete dissociation between P waves and QRS complexes
  • P waves and QRS have independent regular rates
  • Ventricular escape rhythm: rate 20-40 bpm, wide QRS (if ventricular) or narrow QRS (if junctional)
  • Emergency - needs pacemaker

13. BUNDLE BRANCH BLOCKS

Right Bundle Branch Block (RBBB)

Criteria:
  • QRS ≥ 0.12 sec (≥ 120 msec)
  • RSR' pattern ("rabbit ears") in V1
  • Wide, slurred S wave in leads I, V5, V6
  • Secondary T wave changes (T wave inversion in V1-V3)
Mnemonic: "WiRRoW" - W shape in V1 (actually RSR'), M in V6 ... use "RsR' in Right V1"
Causes: Right heart strain (PE, cor pulmonale), congenital heart disease, ischemia, normal variant

Left Bundle Branch Block (LBBB)

Criteria:
  • QRS ≥ 0.12 sec
  • Broad, notched R wave in I, aVL, V5, V6 (no Q wave in V5-V6)
  • QS or rS in V1
  • ST and T wave changes opposite to QRS direction (discordant)
Clinical significance: LBBB almost always indicates significant underlying heart disease (CAD, cardiomyopathy, hypertension). New LBBB in chest pain context = treat as STEMI equivalent (Sgarbossa criteria apply).
Mnemonic: "WiLLiaM MoRRoW" - W in V1 and M in V6 for LBBB; M in V1 and W in V6 for RBBB

14. VENTRICULAR HYPERTROPHY

Left Ventricular Hypertrophy (LVH)

Sokolow-Lyon Criteria (most commonly used):
  • S in V1 + R in V5 or V6 > 35 mm
  • Or: R in aVL > 11 mm
Other features:
  • Strain pattern: ST depression + T wave inversion in lateral leads (I, aVL, V5, V6)
  • Left axis deviation
  • Wide QRS (though < 120 msec)
Causes: Hypertension (most common), aortic stenosis, hypertrophic cardiomyopathy

Right Ventricular Hypertrophy (RVH)

Criteria:
  • R > S in V1 (tall R wave in V1, R ≥ 7 mm)
  • Right axis deviation (> +90°)
  • Strain pattern: ST depression/T inversion in V1-V3, II, III, aVF
Causes: Pulmonary hypertension, pulmonary stenosis, cor pulmonale, congenital heart disease (ASD, VSD)

15. ISCHEMIA AND INFARCTION

Sequence of ECG Changes in STEMI:

TimeECG Change
MinutesHyperacute (tall, peaked) T waves
HoursST elevation
Hours-daysT wave inversion
Days-weeksPathological Q waves form
Weeks-monthsST returns to baseline
PermanentQ waves may persist

Pathological Q Waves

  • Width ≥ 0.04 sec (1 small box) or duration ≥ 40 msec
  • Depth ≥ 25% of R wave amplitude in the same complex
  • Represent dead/electrically silent myocardium (transmural infarction)
  • Note: Septal Q waves in I, aVL, V5, V6 are normal (small, narrow)

Localizing the Infarct by Territory:

TerritoryLeads with changesCoronary Artery
InferiorII, III, aVFRCA (80%), LCx (20%)
LateralI, aVL, V5, V6LCx or diagonal
AnteriorV1-V4LAD
SeptalV1-V2Septal perforators of LAD
PosteriorTall R and ST depression in V1-V2 (reciprocal)RCA or LCx
Right ventricularV1, ST elevation in V4RRCA

STEMI vs. Pericarditis ST Elevation:

FeatureSTEMIPericarditis
DistributionRegional (one territory)Diffuse (all leads except aVR/V1)
MorphologyConvex ("tombstone")Concave (saddle-shaped)
PR depressionAbsentPresent (pathognomonic)
Reciprocal changesPresentAbsent
Q wavesDevelopDo not develop

16. ELECTROLYTE DISTURBANCES ON ECG

Hyperkalemia (progressive changes with rising K+):

  1. Tall, peaked, narrow ("tented") T waves (earliest sign)
  2. PR prolongation
  3. P wave flattening/disappearance
  4. Wide QRS
  5. Sine wave pattern
  6. VF/asystole (at K+ > 7-8 mEq/L)

Hypokalemia:

  • Flattening of T waves
  • Prominent U waves (most characteristic)
  • ST depression
  • Prolonged QU interval (mistaken for long QT)
  • Risk of TdP at severe levels

Hypercalcemia:

  • Short QT interval (shortened ST segment)
  • Broad T waves
  • J waves (Osborn waves) at very high levels

Hypocalcemia:

  • Prolonged QT interval (prolonged ST segment)
  • Risk of TdP

Hypomagnesemia:

  • PR prolongation
  • Prolonged QT
  • T wave changes
  • Risk of TdP (often co-exists with hypokalemia)

17. DRUG EFFECTS ON ECG

DrugECG Effect
Digoxin"Reverse tick" ST depression, shortened QT, T wave inversion, PR prolongation, various arrhythmias
Beta-blockersBradycardia, PR prolongation
Class Ia antiarrhythmics (quinidine)QT prolongation, QRS widening
Class Ic (flecainide)QRS widening, PR prolongation
Class III (amiodarone, sotalol)QT prolongation
TCAs (tricyclics)Sinus tachycardia, QRS widening, QT prolongation, right axis deviation
AntipsychoticsQT prolongation
Fluoroquinolones / macrolidesQT prolongation

18. OTHER IMPORTANT ECG PATTERNS

Wolff-Parkinson-White (WPW)

  • Short PR interval (< 120 msec)
  • Delta wave (slurred upstroke of QRS)
  • Widened QRS
  • ST/T changes
  • Caused by accessory pathway (Bundle of Kent) bypassing AV node
  • Risk: pre-excited AF → VF (never use AV-nodal blocking drugs in AF with WPW)

Brugada Pattern

  • RBBB-like pattern + ST elevation in V1-V3 (downsloping/coved type)
  • Associated with sudden cardiac death in structurally normal heart
  • Accentuated by fever, sodium channel blockers, vagal tone

Pulmonary Embolism (PE)

  • Most common finding: Sinus tachycardia
  • Classic (but uncommon): S1Q3T3 - deep S in I, Q wave + T inversion in III
  • Right heart strain: RBBB, RAD, P pulmonale
  • T wave inversions in V1-V4

Pericarditis

  • Stage 1: Diffuse ST elevation (concave/saddle-shaped) + PR depression in all leads except aVR/V1 (PR elevated in aVR)
  • Stage 2: ST and PR return to baseline
  • Stage 3: Diffuse T wave inversion
  • Stage 4: ECG normalizes

Hypothermia

  • Sinus bradycardia
  • Osborn (J) waves - positive deflection at J point; most prominent in leads V4-V6
  • QT prolongation
  • Prolonged PR and QRS
  • Shivering artifact

Long QT Syndrome

  • Congenital (LQT1, LQT2, LQT3 - different triggers and T wave morphologies)
  • Acquired (drugs, electrolytes)
  • Risk: Torsades de Pointes (polymorphic VT) → syncope / sudden death

19. QUICK CLINICAL CLUES TABLE

ECG FindingThink Of
Delta wave + short PRWPW
Sawtooth waves at 300 bpmAtrial flutter
Irregularly irregular, no P wavesAtrial fibrillation
Progressive PR prolongation + dropped beatMobitz I (Wenckebach)
Fixed PR + sudden dropped beatMobitz II
P-QRS complete dissociationComplete heart block
RSR' in V1 + wide S in V6RBBB
Broad notched R in V5-V6, no Q in V6LBBB
S1Q3T3 + sinus tachycardiaPulmonary embolism
Diffuse ST elevation + PR depressionPericarditis
Tall peaked T wavesHyperkalemia
Prominent U wavesHypokalemia
Short QTHypercalcemia
Long QT + low K/MgTorsades risk
Osborn (J) wavesHypothermia
Reverse tick ST depressionDigoxin effect

20. KEY FORMULAS SUMMARY

FormulaUse
HR = 300 / (# large boxes)Quick rate estimation
HR = 60,000 / RR interval (msec)Precise rate
QTc = QT / √RRBazett's correction for QT
Sokolow-Lyon: SV1 + RV5/V6 > 35 mmLVH criterion
Pathological Q: width ≥ 0.04 sec, depth ≥ 25% RQ wave = infarction

Sources:
  • Goldman-Cecil Medicine, International Edition (Chapter 42 - Electrocardiography)
  • Medical Physiology (Boron & Boulpaep), Chapter 21 - Box 21-2, Table 21-5
  • Miller's Anesthesia, 10th Edition - Chapter 13 (Electrical Events and the ECG)
  • Roberts & Hedges' Clinical Procedures in Emergency Medicine - Electrocardiography chapter

Create a presentation summarizing ECG interpretation steps

Reading File
Reading File
Reading File
Reading File
Running Command

ls /home/daytona/workspace/ 2>/dev/null || mkdir -p /home/daytona/workspace/

Running Command

mkdir -p /home/daytona/workspace/ecg-pptx && ls /home/daytona/workspace/ecg-pptx

Writing File

~/ecg-pptx/build.js

const pptxgen = require("pptxgenjs");
const { execSync } = require("child_process");

// ── Palette ────────────────────────────────────────────────────────────────
// Deep navy dominant, crimson accent, white / light-steel secondary
const C = {
  navy:       "0D1B2A",   // dominant bg
  navyMid:    "1A2E45",   // card bg
  navyLight:  "1E3A5F",   // lighter card / stripe
  crimson:    "C0392B",   // accent red (ECG trace colour)
  crimsonSoft:"E74C3C",   // lighter accent
  teal:       "1ABC9C",   // positive highlight
  amber:      "F39C12",   // warning / caution
  white:      "FFFFFF",
  offWhite:   "EDF2F7",
  steelGray:  "8FA8C8",   // muted text
  lightGray:  "BDC3C7",
};

// ── Helper utilities ───────────────────────────────────────────────────────
function fetchImages(...urls) {
  const result = execSync(
    `node /home/daytona/skills/shared/scripts/fetch_images.js ${urls.map(u => `"${u}"`).join(" ")}`
  ).toString();
  return JSON.parse(result);
}

// Download key ECG images used throughout the deck
const imgUrls = [
  "https://cdn.orris.care/cdss_images/ef815eeb06c673b405e3c7f9112d1e9ff6fbea96a00a2723b233d384156386bd.png", // ECG waveform diagram
  "https://cdn.orris.care/cdss_images/ed3e36266afd563652d7495682c022c3508452257126640a6ab3375b0b0a7e46.png", // Conduction system
  "https://cdn.orris.care/cdss_images/a768a511d3107d6bff69c3e8cf7b50c4485d458be34be6234f7fc6d4ca4fc3ec.png", // Cardiac cycle
];
console.log("Downloading images...");
const imgs = fetchImages(...imgUrls);
const ecgWaveImg  = imgs[0].base64;  // waveform
const condSysImg  = imgs[1].base64;  // conduction system
const cardCycImg  = imgs[2].base64;  // cardiac cycle

// ── Presentation setup ─────────────────────────────────────────────────────
const pres = new pptxgen();
pres.layout  = "LAYOUT_16x9";
pres.title   = "ECG Interpretation – A Systematic Approach";
pres.author  = "Medical Education";
pres.subject = "Electrocardiography";

// ── Slide helpers ──────────────────────────────────────────────────────────

/** Dark header bar at top of slide */
function addHeaderBar(slide, text, subtext = "") {
  slide.addShape(pres.shapes.RECTANGLE, {
    x: 0, y: 0, w: 10, h: 1.1,
    fill: { color: C.crimson }, line: { color: C.crimson }
  });
  slide.addText(text, {
    x: 0.35, y: 0, w: 9.3, h: subtext ? 0.65 : 1.1,
    fontSize: subtext ? 22 : 26, bold: true, color: C.white,
    valign: subtext ? "bottom" : "middle", margin: 0
  });
  if (subtext) {
    slide.addText(subtext, {
      x: 0.35, y: 0.62, w: 9.3, h: 0.48,
      fontSize: 13, color: "FADADD", italic: true, valign: "top", margin: 0
    });
  }
}

/** Numbered step badge */
function addStepBadge(slide, num, x, y, color = C.teal) {
  slide.addShape(pres.shapes.ELLIPSE, {
    x, y, w: 0.52, h: 0.52,
    fill: { color }, line: { color }
  });
  slide.addText(String(num), {
    x, y, w: 0.52, h: 0.52,
    fontSize: 18, bold: true, color: C.white,
    align: "center", valign: "middle", margin: 0
  });
}

/** Coloured card rectangle */
function addCard(slide, x, y, w, h, fillColor = C.navyMid) {
  slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
    x, y, w, h,
    fill: { color: fillColor },
    line: { color: fillColor },
    rectRadius: 0.08,
    shadow: { type: "outer", color: "000000", blur: 8, offset: 3, angle: 135, opacity: 0.25 }
  });
}

/** Left accent stripe on a card */
function addAccentStripe(slide, x, y, h, color = C.crimson) {
  slide.addShape(pres.shapes.RECTANGLE, {
    x, y, w: 0.07, h,
    fill: { color }, line: { color }
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 1 – Title
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };

  // Red horizontal stripe top
  s.addShape(pres.shapes.RECTANGLE, {
    x: 0, y: 0, w: 10, h: 0.18, fill: { color: C.crimson }, line: { color: C.crimson }
  });
  // Red horizontal stripe bottom
  s.addShape(pres.shapes.RECTANGLE, {
    x: 0, y: 5.44, w: 10, h: 0.18, fill: { color: C.crimson }, line: { color: C.crimson }
  });

  // ECG waveform image – right half, tinted
  s.addImage({ data: ecgWaveImg, x: 4.6, y: 0.9, w: 5.1, h: 3.8, transparency: 35 });

  // Dark overlay panel left
  addCard(s, 0.3, 0.55, 5.2, 4.5, C.navyMid);
  addAccentStripe(s, 0.3, 0.55, 4.5, C.crimson);

  s.addText("ECG Interpretation", {
    x: 0.6, y: 0.75, w: 4.7, h: 1.0,
    fontSize: 32, bold: true, color: C.white, margin: 0
  });
  s.addText("A Systematic Approach", {
    x: 0.6, y: 1.75, w: 4.7, h: 0.6,
    fontSize: 20, color: C.crimsonSoft, bold: true, margin: 0
  });
  s.addShape(pres.shapes.RECTANGLE, {
    x: 0.6, y: 2.42, w: 1.5, h: 0.05, fill: { color: C.steelGray }, line: { color: C.steelGray }
  });
  s.addText([
    { text: "For 3rd Year Medical Students\n", options: { breakLine: true } },
    { text: "Based on Goldman-Cecil Medicine & Medical Physiology" }
  ], {
    x: 0.6, y: 2.6, w: 4.7, h: 1.2,
    fontSize: 12, color: C.steelGray, italic: true, margin: 0
  });

  s.addText("Rate  •  Rhythm  •  Axis  •  Intervals  •  Hypertrophy  •  Ischemia", {
    x: 0.3, y: 4.7, w: 9.4, h: 0.5,
    fontSize: 11, color: C.steelGray, align: "center",
    italic: true, charSpacing: 1, margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 2 – Why ECG & What It Measures
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "What Does the ECG Measure?", "Understanding the fundamentals before systematic interpretation");

  // Conduction system image
  s.addImage({ data: condSysImg, x: 5.6, y: 1.2, w: 4.1, h: 3.5 });

  const items = [
    ["Heart Rate",    "Beats per minute from R-R interval"],
    ["Rhythm",        "Origin & regularity of the pacemaker"],
    ["Axis",          "Net direction of ventricular depolarisation"],
    ["Intervals",     "Conduction time through each structure"],
    ["Morphology",    "Hypertrophy, ischaemia, infarction patterns"],
  ];
  items.forEach(([title, desc], i) => {
    const y = 1.28 + i * 0.76;
    addCard(s, 0.3, y, 5.1, 0.64, C.navyMid);
    addAccentStripe(s, 0.3, y, 0.64, C.teal);
    addStepBadge(s, i + 1, 0.5, y + 0.06, C.teal);
    s.addText(title, {
      x: 1.15, y: y + 0.02, w: 2.0, h: 0.3,
      fontSize: 13, bold: true, color: C.white, margin: 0
    });
    s.addText(desc, {
      x: 1.15, y: y + 0.3, w: 4.0, h: 0.28,
      fontSize: 11, color: C.steelGray, margin: 0
    });
  });

  s.addText("Conduction System", {
    x: 5.6, y: 4.75, w: 4.1, h: 0.3,
    fontSize: 10, color: C.steelGray, align: "center", italic: true, margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 3 – ECG Paper & Calibration
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "ECG Paper & Calibration", "Know your grid before measuring anything");

  // Waveform image right
  s.addImage({ data: ecgWaveImg, x: 5.2, y: 1.2, w: 4.5, h: 3.9 });

  // Two info cards
  const gridData = [
    ["Small Box (1 mm)", "0.04 sec  |  0.1 mV"],
    ["Large Box (5 mm)", "0.20 sec  |  0.5 mV"],
    ["Standard Speed",   "25 mm / second"],
    ["Calibration",      "10 mm = 1 mV"],
    ["Recording Time",   "10 seconds (standard)"],
  ];
  gridData.forEach(([label, val], i) => {
    const y = 1.3 + i * 0.72;
    addCard(s, 0.3, y, 4.75, 0.6, i % 2 === 0 ? C.navyMid : C.navyLight);
    s.addText(label, {
      x: 0.5, y: y + 0.06, w: 2.3, h: 0.25,
      fontSize: 12, bold: true, color: C.offWhite, margin: 0
    });
    s.addText(val, {
      x: 0.5, y: y + 0.3, w: 4.4, h: 0.24,
      fontSize: 12, color: C.teal, bold: true, margin: 0
    });
  });

  s.addText("Normal ECG Waveform with Intervals\n(Goldman-Cecil Medicine)", {
    x: 5.2, y: 5.1, w: 4.5, h: 0.4,
    fontSize: 9.5, color: C.steelGray, align: "center", italic: true, margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 4 – The 12 Leads
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "The 12 Leads – What Each Views", "Each lead is a different vantage point on the same electrical activity");

  const limb = [
    ["I",    "Left arm (+)",    "Lateral"],
    ["II",   "Left leg (+)",    "Inferior"],
    ["III",  "Left leg (+)",    "Inferior"],
    ["aVR",  "Right arm (+)",   "Cavity (inverted)"],
    ["aVL",  "Left arm (+)",    "Lateral"],
    ["aVF",  "Left leg (+)",    "Inferior"],
  ];
  const prec = [
    ["V1", "4th ICS R sternal border", "Septal / RV"],
    ["V2", "4th ICS L sternal border", "Septal"],
    ["V3", "Between V2 & V4",          "Anterior"],
    ["V4", "5th ICS midclavicular",    "Anterior"],
    ["V5", "Anterior axillary line",   "Lateral"],
    ["V6", "Midaxillary line",         "Lateral"],
  ];

  // Limb leads table
  s.addText("LIMB LEADS", {
    x: 0.25, y: 1.2, w: 4.6, h: 0.32,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 2, margin: 0
  });
  const limbRows = [
    [{ text: "Lead", options: { bold: true, color: C.white } },
     { text: "Positive Electrode", options: { bold: true, color: C.white } },
     { text: "Territory", options: { bold: true, color: C.white } }],
    ...limb.map(([l, e, t]) => [
      { text: l, options: { bold: true, color: C.teal } },
      { text: e, options: { color: C.offWhite } },
      { text: t, options: { color: C.steelGray } }
    ])
  ];
  s.addTable(limbRows, {
    x: 0.25, y: 1.52, w: 4.6, h: 2.3,
    border: { pt: 0.5, color: C.navyLight },
    fill: { color: C.navyMid },
    colW: [0.8, 2.1, 1.7],
    fontSize: 11,
    rowH: 0.3,
  });

  // Precordial leads table
  s.addText("PRECORDIAL LEADS", {
    x: 5.2, y: 1.2, w: 4.6, h: 0.32,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 2, margin: 0
  });
  const precRows = [
    [{ text: "Lead", options: { bold: true, color: C.white } },
     { text: "Position", options: { bold: true, color: C.white } },
     { text: "Territory", options: { bold: true, color: C.white } }],
    ...prec.map(([l, p, t]) => [
      { text: l, options: { bold: true, color: C.amber } },
      { text: p, options: { color: C.offWhite } },
      { text: t, options: { color: C.steelGray } }
    ])
  ];
  s.addTable(precRows, {
    x: 5.2, y: 1.52, w: 4.6, h: 2.3,
    border: { pt: 0.5, color: C.navyLight },
    fill: { color: C.navyMid },
    colW: [0.8, 2.2, 1.6],
    fontSize: 11,
    rowH: 0.3,
  });

  // Key rule
  addCard(s, 0.25, 4.05, 9.5, 0.72, C.navyLight);
  addAccentStripe(s, 0.25, 4.05, 0.72, C.amber);
  s.addText("Key Rule: ", {
    x: 0.5, y: 4.12, w: 1.1, h: 0.3,
    fontSize: 12, bold: true, color: C.amber, margin: 0
  });
  s.addText("A positive deflection = wavefront travelling TOWARD the positive electrode of that lead.", {
    x: 1.55, y: 4.12, w: 7.9, h: 0.3,
    fontSize: 12, color: C.offWhite, margin: 0
  });
  s.addText("Reciprocal changes in opposite leads confirm the finding.", {
    x: 1.55, y: 4.44, w: 7.9, h: 0.25,
    fontSize: 11, color: C.steelGray, italic: true, margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 5 – The Normal Waveforms
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "The Normal ECG Waveforms", "What each deflection represents physiologically");

  const waves = [
    { name: "P Wave",      color: C.teal,       text: "Atrial depolarisation  |  < 120 msec  |  < 2.5 mm limb leads" },
    { name: "PR Interval", color: C.steelGray,  text: "Atrial dep. → ventricular dep. (AV node delay)  |  90–200 msec" },
    { name: "QRS Complex", color: C.crimsonSoft,text: "Ventricular depolarisation  |  75–110 msec" },
    { name: "ST Segment",  color: C.amber,      text: "Early ventricular repolarisation (plateau)  |  Isoelectric = normal" },
    { name: "T Wave",      color: C.teal,       text: "Ventricular repolarisation  |  Upright I, II, V3–V6" },
    { name: "QT Interval", color: C.crimsonSoft,text: "Total ventricular activity  |  QTc = QT / √RR  |  ♂ ≤450 ms  ♀ ≤460 ms" },
    { name: "U Wave",      color: C.steelGray,  text: "Purkinje repolarisation (debated)  |  Prominent → hypokalemia" },
  ];

  waves.forEach((w, i) => {
    const col = i < 4 ? 0 : 1;
    const row = i < 4 ? i : i - 4;
    const x = col === 0 ? 0.25 : 5.1;
    const y = 1.22 + row * 0.88;
    addCard(s, x, y, 4.6, 0.74, C.navyMid);
    addAccentStripe(s, x, y, 0.74, w.color);
    s.addText(w.name, {
      x: x + 0.2, y: y + 0.04, w: 4.1, h: 0.28,
      fontSize: 13, bold: true, color: w.color, margin: 0
    });
    s.addText(w.text, {
      x: x + 0.2, y: y + 0.34, w: 4.25, h: 0.34,
      fontSize: 10.5, color: C.offWhite, margin: 0
    });
  });

  // ECG image at bottom right of col 2 (fills remaining space)
  s.addImage({ data: ecgWaveImg, x: 5.1, y: 4.46, w: 4.6, h: 1.05, transparency: 20 });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 6 – Normal Intervals Table
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "Normal Interval Reference Table", "Memorise these — they define normal vs. abnormal");

  const rows = [
    [{ text: "Parameter",      options: { bold: true, color: C.white, fill: { color: C.crimson } } },
     { text: "Normal Range",   options: { bold: true, color: C.white, fill: { color: C.crimson } } },
     { text: "If Abnormal…",   options: { bold: true, color: C.white, fill: { color: C.crimson } } }],
    [{ text: "Heart Rate",         options: { color: C.teal, bold: true } },
     { text: "50–100 bpm",         options: { color: C.offWhite } },
     { text: "Brady / Tachycardia", options: { color: C.steelGray } }],
    [{ text: "P Wave Duration",    options: { color: C.teal, bold: true } },
     { text: "< 120 msec",          options: { color: C.offWhite } },
     { text: "Atrial enlargement",  options: { color: C.steelGray } }],
    [{ text: "PR Interval",        options: { color: C.teal, bold: true } },
     { text: "90–200 msec",         options: { color: C.offWhite } },
     { text: "AV block (↑) / WPW (↓)", options: { color: C.steelGray } }],
    [{ text: "QRS Duration",       options: { color: C.teal, bold: true } },
     { text: "75–110 msec",         options: { color: C.offWhite } },
     { text: "Bundle branch block > 120 msec", options: { color: C.steelGray } }],
    [{ text: "QTc  (Male)",        options: { color: C.amber, bold: true } },
     { text: "390–450 msec",        options: { color: C.offWhite } },
     { text: "TdP risk if prolonged", options: { color: C.steelGray } }],
    [{ text: "QTc  (Female)",      options: { color: C.amber, bold: true } },
     { text: "390–460 msec",        options: { color: C.offWhite } },
     { text: "TdP risk if prolonged", options: { color: C.steelGray } }],
    [{ text: "QRS Axis",           options: { color: C.teal, bold: true } },
     { text: "−30° to +90°",        options: { color: C.offWhite } },
     { text: "LAD / RAD",           options: { color: C.steelGray } }],
  ];

  s.addTable(rows, {
    x: 0.4, y: 1.25, w: 9.2, h: 3.95,
    border: { pt: 0.5, color: C.navyLight },
    fill: { color: C.navyMid },
    colW: [2.6, 2.8, 3.8],
    fontSize: 12.5,
    rowH: 0.46,
  });

  // Bazett formula box
  addCard(s, 0.4, 5.28, 9.2, 0.28, C.navyLight);
  s.addText("Bazett's Formula:  QTc = QT (sec) ÷ √RR (sec)   |   Measure QT in leads II, V5, V6 – use the longest", {
    x: 0.6, y: 5.3, w: 8.8, h: 0.24,
    fontSize: 11, color: C.amber, italic: true, bold: true, margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 7 – Step-by-Step Interpretation Framework
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "10-Step Systematic Approach", "Use this sequence every single time — never skip a step");

  const steps = [
    ["Rate",         "Count large boxes between R waves → 300/boxes", C.teal],
    ["Rhythm",       "Regular or irregular? P before every QRS?",     C.teal],
    ["P Wave",       "Present, upright I & II, normal morphology?",   C.teal],
    ["PR Interval",  "Normal 90–200 msec? Prolonged = AV block",      C.amber],
    ["QRS Duration", "< 110 msec? Widened = BBB / preexcitation",     C.amber],
    ["QRS Axis",     "Leads I & aVF: both positive = normal axis",    C.amber],
    ["ST Segment",   "Isoelectric? Elevation or depression?",         C.crimsonSoft],
    ["T Wave",       "Upright I, II, V3–V6? Inverted = ischaemia?",   C.crimsonSoft],
    ["QT Interval",  "Calculate QTc — prolonged = TdP risk",          C.crimsonSoft],
    ["Interpretation","Synthesise all findings → clinical diagnosis",  C.steelGray],
  ];

  steps.forEach(([ title, desc, col ], i) => {
    const column = i < 5 ? 0 : 1;
    const row    = i < 5 ? i : i - 5;
    const x = column === 0 ? 0.25 : 5.1;
    const y = 1.2 + row * 0.82;
    addCard(s, x, y, 4.6, 0.7, C.navyMid);
    addStepBadge(s, i + 1, x + 0.1, y + 0.09, col);
    s.addText(title, {
      x: x + 0.75, y: y + 0.04, w: 3.7, h: 0.28,
      fontSize: 13, bold: true, color: col, margin: 0
    });
    s.addText(desc, {
      x: x + 0.75, y: y + 0.35, w: 3.75, h: 0.3,
      fontSize: 10.5, color: C.offWhite, margin: 0
    });
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 8 – Heart Rate & Rhythm
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "Steps 1 & 2: Rate and Rhythm", "Foundation of every ECG read");

  // Rate methods
  s.addText("HEART RATE METHODS", {
    x: 0.3, y: 1.25, w: 4.5, h: 0.32,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 2, margin: 0
  });
  const rateMethods = [
    ["Quick Method", "300 ÷ number of large boxes between R waves\n300 → 150 → 100 → 75 → 60 → 50"],
    ["Precise Method", "60,000 ÷ R-R interval in milliseconds"],
    ["Irregular Rhythm", "Count QRS complexes in 10 sec strip × 6"],
  ];
  rateMethods.forEach(([m, d], i) => {
    const y = 1.62 + i * 0.88;
    addCard(s, 0.3, y, 4.5, 0.76, C.navyMid);
    addAccentStripe(s, 0.3, y, 0.76, C.teal);
    s.addText(m, { x: 0.55, y: y + 0.06, w: 4.0, h: 0.26, fontSize: 12.5, bold: true, color: C.teal, margin: 0 });
    s.addText(d, { x: 0.55, y: y + 0.35, w: 4.1, h: 0.36, fontSize: 11, color: C.offWhite, margin: 0 });
  });

  // Rhythm criteria
  s.addText("NORMAL SINUS RHYTHM CRITERIA", {
    x: 5.1, y: 1.25, w: 4.7, h: 0.32,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 2, margin: 0
  });
  const nsrItems = [
    "Regular rhythm at 60–100 bpm",
    "P wave upright in leads I, II, aVF",
    "P wave inverted in aVR",
    "Every P wave followed by a QRS",
    "Every QRS preceded by a P wave",
    "PR interval 120–200 msec",
    "QRS duration < 120 msec",
    "Normal axis (−30° to +90°)",
  ];
  addCard(s, 5.1, 1.62, 4.7, 3.6, C.navyMid);
  addAccentStripe(s, 5.1, 1.62, 3.6, C.amber);
  s.addText(nsrItems.map(t => ({ text: t, options: { bullet: { indent: 15 }, breakLine: true } }))
    .map((o, i) => i === nsrItems.length - 1 ? { ...o, options: { ...o.options, breakLine: false } } : o),
    { x: 5.35, y: 1.72, w: 4.3, h: 3.3, fontSize: 12, color: C.offWhite, margin: 0, lineSpacingMultiple: 1.4 }
  );

  // Rate quick table
  addCard(s, 0.3, 5.12, 4.5, 0.44, C.navyLight);
  s.addText("< 60 bpm = Bradycardia   |   60–100 = Normal   |   > 100 bpm = Tachycardia", {
    x: 0.35, y: 5.15, w: 4.4, h: 0.38,
    fontSize: 11, color: C.amber, bold: true, align: "center", margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 9 – QRS Axis
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "Step 6: QRS Axis", "Use leads I and aVF for rapid axis determination");

  // Axis quadrant diagram using shapes
  const cx = 5.0, cy = 3.2, r = 1.6;
  // Circle background
  s.addShape(pres.shapes.ELLIPSE, {
    x: cx - r, y: cy - r, w: r * 2, h: r * 2,
    fill: { color: C.navyMid }, line: { color: C.steelGray, pt: 1.5 }
  });
  // Horizontal axis
  s.addShape(pres.shapes.LINE, { x: cx - r, y: cy, w: r * 2, h: 0, line: { color: C.steelGray, pt: 1.5 } });
  // Vertical axis
  s.addShape(pres.shapes.LINE, { x: cx, y: cy - r, w: 0, h: r * 2, line: { color: C.steelGray, pt: 1.5 } });

  // Quadrant labels
  s.addText("NORMAL\n(−30° to +90°)\nI ✓  aVF ✓", { x: cx + 0.1, y: cy + 0.08, w: 1.5, h: 0.7, fontSize: 10, color: C.teal, bold: true, align: "center", margin: 0 });
  s.addText("LAD\n(< −30°)\nI ✓  aVF ✗", { x: cx - 1.55, y: cy + 0.08, w: 1.45, h: 0.7, fontSize: 10, color: C.amber, bold: true, align: "center", margin: 0 });
  s.addText("RAD\n(> +90°)\nI ✗  aVF ✓", { x: cx + 0.1, y: cy - 0.78, w: 1.45, h: 0.7, fontSize: 10, color: C.crimsonSoft, bold: true, align: "center", margin: 0 });
  s.addText("EXTREME\nNW axis\nI ✗  aVF ✗", { x: cx - 1.55, y: cy - 0.78, w: 1.45, h: 0.7, fontSize: 10, color: C.steelGray, bold: true, align: "center", margin: 0 });

  // Lead labels
  s.addText("aVF (+)", { x: cx + 0.1, y: cy + r + 0.05, w: 0.9, h: 0.28, fontSize: 10, color: C.steelGray, margin: 0 });
  s.addText("aVF (−)", { x: cx + 0.1, y: cy - r - 0.3, w: 0.9, h: 0.28, fontSize: 10, color: C.steelGray, margin: 0 });
  s.addText("I (+)", { x: cx + r + 0.05, y: cy, w: 0.7, h: 0.28, fontSize: 10, color: C.steelGray, margin: 0 });
  s.addText("I (−)", { x: cx - r - 0.75, y: cy, w: 0.7, h: 0.28, fontSize: 10, color: C.steelGray, margin: 0 });

  // LAD causes
  s.addText("LEFT AXIS DEVIATION (LAD)", {
    x: 0.25, y: 1.2, w: 4.3, h: 0.32,
    fontSize: 11, bold: true, color: C.amber, charSpacing: 1.5, margin: 0
  });
  const ladCauses = ["Left anterior fascicular block (most common)", "Left ventricular hypertrophy", "Inferior STEMI", "WPW (right-sided accessory pathway)"];
  addCard(s, 0.25, 1.55, 4.3, 1.6, C.navyMid);
  addAccentStripe(s, 0.25, 1.55, 1.6, C.amber);
  s.addText(ladCauses.map((t, i) => ({ text: t, options: { bullet: { indent: 15 }, breakLine: i < ladCauses.length - 1 } })), {
    x: 0.5, y: 1.65, w: 3.9, h: 1.4, fontSize: 11.5, color: C.offWhite, lineSpacingMultiple: 1.45, margin: 0
  });

  // RAD causes
  s.addText("RIGHT AXIS DEVIATION (RAD)", {
    x: 0.25, y: 3.28, w: 4.3, h: 0.32,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 1.5, margin: 0
  });
  const radCauses = ["Right ventricular hypertrophy", "Left posterior fascicular block", "Pulmonary embolism / cor pulmonale", "Normal in children & tall thin adults"];
  addCard(s, 0.25, 3.62, 4.3, 1.6, C.navyMid);
  addAccentStripe(s, 0.25, 3.62, 1.6, C.crimsonSoft);
  s.addText(radCauses.map((t, i) => ({ text: t, options: { bullet: { indent: 15 }, breakLine: i < radCauses.length - 1 } })), {
    x: 0.5, y: 3.72, w: 3.9, h: 1.4, fontSize: 11.5, color: C.offWhite, lineSpacingMultiple: 1.45, margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 10 – Bundle Branch Blocks
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "Bundle Branch Blocks", "QRS ≥ 120 msec + specific morphology");

  // RBBB left column
  s.addText("RIGHT BUNDLE BRANCH BLOCK", {
    x: 0.25, y: 1.2, w: 4.6, h: 0.32,
    fontSize: 11, bold: true, color: C.amber, charSpacing: 1.5, margin: 0
  });
  addCard(s, 0.25, 1.55, 4.6, 3.75, C.navyMid);
  addAccentStripe(s, 0.25, 1.55, 3.75, C.amber);

  const rbbItems = [
    ["QRS Duration", "≥ 120 msec (3 small boxes)"],
    ["V1 Pattern",   "RSR' – 'rabbit ears' (M-shape)"],
    ["I, V5, V6",    "Wide, slurred S wave"],
    ["T waves",      "Inversion V1–V3 (secondary change)"],
    ["Causes",       "PE, cor pulmonale, congenital, ischaemia, normal variant"],
    ["Mnemonic",     "R in the Right: RSR' in V1"],
  ];
  rbbItems.forEach(([k, v], i) => {
    const y = 1.7 + i * 0.55;
    s.addText(k + ": ", { x: 0.5, y, w: 1.5, h: 0.27, fontSize: 11.5, bold: true, color: C.amber, margin: 0 });
    s.addText(v,        { x: 1.9, y, w: 2.8, h: 0.27, fontSize: 11.5, color: C.offWhite, margin: 0 });
  });

  // LBBB right column
  s.addText("LEFT BUNDLE BRANCH BLOCK", {
    x: 5.15, y: 1.2, w: 4.6, h: 0.32,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 1.5, margin: 0
  });
  addCard(s, 5.15, 1.55, 4.6, 3.75, C.navyMid);
  addAccentStripe(s, 5.15, 1.55, 3.75, C.crimsonSoft);

  const lbbItems = [
    ["QRS Duration", "≥ 120 msec"],
    ["V1 Pattern",   "Broad QS or rS (W-shape)"],
    ["I, V5, V6",    "Broad, notched R; no Q waves in V5-V6"],
    ["T waves",      "Discordant (opposite to QRS direction)"],
    ["Significance", "Almost always pathological (CAD, cardiomyopathy, HTN)"],
    ["Mnemonic",     "WiLLiaM MoRRoW: W in V1, M in V6 for LBBB"],
  ];
  lbbItems.forEach(([k, v], i) => {
    const y = 1.7 + i * 0.55;
    s.addText(k + ": ", { x: 5.4, y, w: 1.5, h: 0.27, fontSize: 11.5, bold: true, color: C.crimsonSoft, margin: 0 });
    s.addText(v,        { x: 6.8, y, w: 2.8, h: 0.27, fontSize: 11.5, color: C.offWhite, margin: 0 });
  });

  // Bottom note
  addCard(s, 0.25, 5.38, 9.5, 0.2, C.navyLight);
  s.addText("New LBBB + chest pain = treat as STEMI equivalent  |  Apply Sgarbossa criteria for ischaemia diagnosis", {
    x: 0.35, y: 5.39, w: 9.3, h: 0.18,
    fontSize: 10.5, color: C.amber, bold: true, align: "center", margin: 0
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 11 – Ischaemia & Infarction
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "Ischaemia & Infarction Patterns", "ST changes and Q waves localise the territory");

  // Timeline of STEMI changes
  s.addText("STEMI EVOLUTION", {
    x: 0.25, y: 1.2, w: 9.5, h: 0.3,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 2, margin: 0
  });

  const stemiStages = [
    ["Minutes",       "Hyperacute T waves\n(tall, peaked)",      C.amber],
    ["Hours",         "ST elevation\n(convex / tombstone)",       C.crimson],
    ["Hours–Days",    "T wave inversion",                         C.crimsonSoft],
    ["Days–Weeks",    "Pathological Q waves\nform",               C.steelGray],
    ["Persistent",    "Q waves remain\n(scar)",                   C.navyLight],
  ];
  stemiStages.forEach(([t, d, col], i) => {
    const x = 0.25 + i * 1.9;
    addCard(s, x, 1.55, 1.75, 1.3, col === C.navyLight ? C.navyMid : C.navyMid);
    addAccentStripe(s, x, 1.55, 1.3, col);
    s.addText(t, { x: x + 0.15, y: 1.6, w: 1.45, h: 0.3, fontSize: 11, bold: true, color: col, margin: 0 });
    s.addText(d, { x: x + 0.15, y: 1.92, w: 1.5, h: 0.55, fontSize: 10.5, color: C.offWhite, margin: 0 });
  });

  // Territory table
  s.addText("INFARCT LOCALISATION", {
    x: 0.25, y: 3.0, w: 9.5, h: 0.3,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 2, margin: 0
  });

  const terrRows = [
    [{ text: "Territory",  options: { bold: true, color: C.white, fill: { color: C.crimson } } },
     { text: "Leads",      options: { bold: true, color: C.white, fill: { color: C.crimson } } },
     { text: "Artery",     options: { bold: true, color: C.white, fill: { color: C.crimson } } }],
    ["Inferior",    "II, III, aVF",   "RCA (80%) / LCx (20%)"],
    ["Lateral",     "I, aVL, V5-V6",  "LCx or diagonal"],
    ["Anterior",    "V1–V4",          "LAD"],
    ["Septal",      "V1–V2",          "Septal perforators (LAD)"],
    ["Posterior",   "Tall R + ST↓ in V1-V2", "RCA or LCx"],
    ["Right Ventricle", "V4R (RV lead)",  "RCA (proximal)"],
  ];
  const formattedRows = terrRows.map((row, i) => {
    if (i === 0) return row;
    return (row as string[]).map((cell, j) => ({
      text: cell,
      options: { color: j === 0 ? C.teal : j === 1 ? C.offWhite : C.steelGray }
    }));
  });

  s.addTable(formattedRows, {
    x: 0.25, y: 3.33, w: 9.5, h: 2.2,
    border: { pt: 0.5, color: C.navyLight },
    fill: { color: C.navyMid },
    colW: [2.5, 3.5, 3.5],
    fontSize: 12,
    rowH: 0.34,
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 12 – Common Arrhythmias Quick Reference
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "Common Arrhythmias – Quick Reference", "Recognise the pattern, identify the mechanism");

  const arrhythmias = [
    { name: "Sinus Tachycardia",  features: "Rate > 100, normal P waves, regular, narrow QRS",                    color: C.teal },
    { name: "Sinus Bradycardia",  features: "Rate < 60, normal P waves, otherwise normal",                        color: C.teal },
    { name: "Atrial Fibrillation", features: "Irregularly irregular, no P waves, variable rate, narrow QRS",      color: C.amber },
    { name: "Atrial Flutter",     features: "Sawtooth at 300 bpm, usually 2:1 block → ventricular rate ~150",    color: C.amber },
    { name: "SVT (AVNRT/AVRT)",   features: "Regular narrow-complex tachycardia 150–250 bpm, P buried in QRS",   color: C.amber },
    { name: "VT",                 features: "≥3 wide QRS > 100 bpm, AV dissociation, fusion/capture beats",      color: C.crimsonSoft },
    { name: "VF",                 features: "Chaotic irregular wide complexes, no output – cardiac arrest",       color: C.crimson },
    { name: "1° AV Block",        features: "PR > 200 msec, all P waves conduct, usually benign",                color: C.steelGray },
    { name: "Mobitz I (Wenckebach)", features: "Progressive PR prolongation → dropped QRS → repeats",            color: C.amber },
    { name: "Mobitz II",          features: "Fixed PR, sudden dropped QRS – below AV node, serious",             color: C.crimsonSoft },
    { name: "Complete Heart Block", features: "P–QRS complete dissociation, escape rhythm – emergency",          color: C.crimson },
  ];

  // Two columns
  const col1 = arrhythmias.slice(0, 6);
  const col2 = arrhythmias.slice(6);

  [[col1, 0.25], [col2, 5.1]].forEach(([items, xBase]) => {
    (items as typeof arrhythmias).forEach((arr, i) => {
      const y = 1.2 + i * 0.7;
      addCard(s, xBase as number, y, 4.6, 0.6, C.navyMid);
      addAccentStripe(s, xBase as number, y, 0.6, arr.color);
      s.addText(arr.name, {
        x: (xBase as number) + 0.2, y: y + 0.04, w: 4.2, h: 0.25,
        fontSize: 12, bold: true, color: arr.color, margin: 0
      });
      s.addText(arr.features, {
        x: (xBase as number) + 0.2, y: y + 0.31, w: 4.2, h: 0.25,
        fontSize: 10.5, color: C.offWhite, margin: 0
      });
    });
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 13 – Electrolyte & Drug Effects
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "Electrolyte & Drug Effects on ECG", "High-yield for exams and clinical practice");

  // Electrolytes table
  s.addText("ELECTROLYTES", {
    x: 0.25, y: 1.22, w: 5.5, h: 0.3,
    fontSize: 11, bold: true, color: C.teal, charSpacing: 2, margin: 0
  });
  const elecRows = [
    [{ text: "Condition", options: { bold: true, color: C.white, fill: { color: C.navyLight } } },
     { text: "Key ECG Finding", options: { bold: true, color: C.white, fill: { color: C.navyLight } } }],
    [{ text: "Hyperkalemia (early)",  options: { color: C.amber } }, { text: "Tall peaked narrow T waves", options: { color: C.offWhite } }],
    [{ text: "Hyperkalemia (severe)", options: { color: C.crimson } }, { text: "Widened QRS → sine wave → VF", options: { color: C.offWhite } }],
    [{ text: "Hypokalemia",           options: { color: C.teal } }, { text: "Flat T waves, prominent U waves, long QU", options: { color: C.offWhite } }],
    [{ text: "Hypercalcemia",         options: { color: C.amber } }, { text: "Short QT interval (short ST segment)", options: { color: C.offWhite } }],
    [{ text: "Hypocalcemia",          options: { color: C.steelGray } }, { text: "Long QT interval (long ST segment)", options: { color: C.offWhite } }],
    [{ text: "Hypomagnesemia",        options: { color: C.teal } }, { text: "Long QT, TdP risk (often + hypoK)", options: { color: C.offWhite } }],
  ];
  s.addTable(elecRows, {
    x: 0.25, y: 1.55, w: 4.6, h: 2.8,
    border: { pt: 0.5, color: C.navyLight },
    fill: { color: C.navyMid },
    colW: [2.2, 2.4],
    fontSize: 11.5, rowH: 0.39,
  });

  // Drugs table
  s.addText("DRUGS", {
    x: 5.15, y: 1.22, w: 4.6, h: 0.3,
    fontSize: 11, bold: true, color: C.amber, charSpacing: 2, margin: 0
  });
  const drugRows = [
    [{ text: "Drug", options: { bold: true, color: C.white, fill: { color: C.navyLight } } },
     { text: "ECG Effect", options: { bold: true, color: C.white, fill: { color: C.navyLight } } }],
    [{ text: "Digoxin",        options: { color: C.amber } }, { text: "Reverse tick ST↓, short QT, ↑PR", options: { color: C.offWhite } }],
    [{ text: "Beta-blockers",  options: { color: C.steelGray } }, { text: "Bradycardia, ↑PR", options: { color: C.offWhite } }],
    [{ text: "Class Ia (quinidine)", options: { color: C.crimsonSoft } }, { text: "↑QT, wide QRS", options: { color: C.offWhite } }],
    [{ text: "Class III (amiodarone)", options: { color: C.crimsonSoft } }, { text: "↑QT, bradycardia", options: { color: C.offWhite } }],
    [{ text: "TCAs",           options: { color: C.crimson } }, { text: "Sinus tach, wide QRS, ↑QT, RAD", options: { color: C.offWhite } }],
    [{ text: "Fluoroquinolones / antipsychotics", options: { color: C.amber } }, { text: "↑QT → TdP risk", options: { color: C.offWhite } }],
  ];
  s.addTable(drugRows, {
    x: 5.15, y: 1.55, w: 4.6, h: 2.8,
    border: { pt: 0.5, color: C.navyLight },
    fill: { color: C.navyMid },
    colW: [2.3, 2.3],
    fontSize: 11.5, rowH: 0.39,
  });

  // Special patterns box
  s.addText("SPECIAL PATTERNS", {
    x: 0.25, y: 4.5, w: 9.5, h: 0.3,
    fontSize: 11, bold: true, color: C.crimsonSoft, charSpacing: 2, margin: 0
  });
  const specials = [
    ["WPW",       "Short PR + delta wave + wide QRS",          C.amber],
    ["Brugada",   "Coved ST elevation V1-V3 + RBBB-like",      C.crimsonSoft],
    ["PE",        "Sinus tach; S1Q3T3; RBBB; T inv V1-V4",     C.teal],
    ["Hypothermia","Sinus brady + Osborn (J) waves",            C.steelGray],
  ];
  specials.forEach(([name, desc, col], i) => {
    const x = 0.25 + i * 2.45;
    addCard(s, x, 4.84, 2.3, 0.72, C.navyMid);
    addAccentStripe(s, x, 4.84, 0.72, col as string);
    s.addText(name as string, { x: x + 0.18, y: 4.89, w: 1.95, h: 0.26, fontSize: 12, bold: true, color: col as string, margin: 0 });
    s.addText(desc as string, { x: x + 0.18, y: 5.16, w: 1.95, h: 0.36, fontSize: 10, color: C.offWhite, margin: 0 });
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 14 – Quick Clues Cheat Sheet
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };
  addHeaderBar(s, "ECG Quick Clues – Cheat Sheet", "One finding → think of …");

  const clues = [
    ["Delta wave + short PR",         "WPW syndrome",                C.amber],
    ["Sawtooth waves ~300 bpm",       "Atrial flutter",              C.teal],
    ["Irregularly irregular, no P",   "Atrial fibrillation",         C.teal],
    ["Progressive PR → dropped beat", "Mobitz I (Wenckebach)",       C.steelGray],
    ["Fixed PR + sudden dropped QRS", "Mobitz II",                   C.crimsonSoft],
    ["P-QRS complete dissociation",   "Complete heart block",        C.crimson],
    ["RSR' in V1 + wide S in V6",     "RBBB",                        C.amber],
    ["Broad notched R V5-V6, no Q",   "LBBB",                        C.crimsonSoft],
    ["S1Q3T3 + sinus tachycardia",    "Pulmonary embolism",          C.teal],
    ["Diffuse ST↑ + PR depression",   "Pericarditis",                C.steelGray],
    ["Tall peaked T waves",           "Hyperkalemia (early)",        C.amber],
    ["Prominent U waves",             "Hypokalemia",                 C.teal],
    ["Short QT interval",             "Hypercalcemia",               C.steelGray],
    ["Long QT + low K/Mg",            "TdP risk",                    C.crimsonSoft],
    ["Osborn (J) waves",              "Hypothermia",                 C.steelGray],
    ["Reverse tick ST depression",    "Digoxin effect",              C.amber],
  ];

  const half = 8;
  [[clues.slice(0, half), 0.25], [clues.slice(half), 5.1]].forEach(([items, xBase]) => {
    (items as typeof clues).forEach(([ecg, dx, col], i) => {
      const y = 1.2 + i * 0.52;
      addCard(s, xBase as number, y, 4.6, 0.44, C.navyMid);
      addAccentStripe(s, xBase as number, y, 0.44, col as string);
      s.addText(ecg as string, {
        x: (xBase as number) + 0.2, y: y + 0.04, w: 2.1, h: 0.36,
        fontSize: 11, color: C.offWhite, margin: 0
      });
      s.addText("→ " + (dx as string), {
        x: (xBase as number) + 2.3, y: y + 0.04, w: 2.2, h: 0.36,
        fontSize: 11, bold: true, color: col as string, margin: 0
      });
    });
  });
}

// ══════════════════════════════════════════════════════════════════════════
//  SLIDE 15 – Summary / Closing
// ══════════════════════════════════════════════════════════════════════════
{
  const s = pres.addSlide();
  s.background = { color: C.navy };

  // Full crimson top bar
  s.addShape(pres.shapes.RECTANGLE, {
    x: 0, y: 0, w: 10, h: 0.18, fill: { color: C.crimson }, line: { color: C.crimson }
  });
  s.addShape(pres.shapes.RECTANGLE, {
    x: 0, y: 5.44, w: 10, h: 0.18, fill: { color: C.crimson }, line: { color: C.crimson }
  });

  s.addText("Always Approach the ECG Systematically", {
    x: 0.5, y: 0.35, w: 9, h: 0.7,
    fontSize: 28, bold: true, color: C.white, align: "center", margin: 0
  });

  const pillars = [
    ["1  Rate",       "300 ÷ large boxes"],
    ["2  Rhythm",     "Regular? P→QRS?"],
    ["3  P Wave",     "Upright I & II?"],
    ["4  PR Interval","90–200 msec"],
    ["5  QRS",        "< 110 msec"],
    ["6  Axis",       "I & aVF positive?"],
    ["7  ST Segment", "Isoelectric?"],
    ["8  T Wave",     "Upright V3–V6?"],
    ["9  QTc",        "≤ 450 / 460 msec"],
    ["10 Synthesise", "Clinical context"],
  ];

  pillars.forEach(([step, hint], i) => {
    const col = i % 5;
    const row = Math.floor(i / 5);
    const x = 0.25 + col * 1.92;
    const y = 1.25 + row * 1.6;
    const accent = i < 3 ? C.teal : i < 6 ? C.amber : i < 9 ? C.crimsonSoft : C.steelGray;
    addCard(s, x, y, 1.78, 1.38, C.navyMid);
    s.addShape(pres.shapes.RECTANGLE, {
      x, y, w: 1.78, h: 0.4, fill: { color: accent }, line: { color: accent }
    });
    s.addText(step, {
      x: x + 0.08, y: y + 0.06, w: 1.62, h: 0.28,
      fontSize: 12, bold: true, color: C.white, margin: 0
    });
    s.addText(hint, {
      x: x + 0.08, y: y + 0.52, w: 1.62, h: 0.72,
      fontSize: 11, color: C.steelGray, align: "center", valign: "middle", margin: 0
    });
  });

  s.addText("Based on Goldman-Cecil Medicine  |  Medical Physiology (Boron & Boulpaep)  |  Miller's Anesthesia", {
    x: 0.3, y: 5.05, w: 9.4, h: 0.28,
    fontSize: 9.5, color: C.steelGray, align: "center", italic: true, margin: 0
  });
}

// ── Write file ─────────────────────────────────────────────────────────────
const outPath = "/home/daytona/workspace/ecg-pptx/ECG_Interpretation.pptx";
pres.writeFile({ fileName: outPath }).then(() => {
  console.log("✅ Saved: " + outPath);
}).catch(err => {
  console.error("❌ Error:", err);
  process.exit(1);
});
Running Command

cd /home/daytona/workspace/ecg-pptx && node build.js 2>&1

Running Command

grep -n " as " /home/daytona/workspace/ecg-pptx/build.js

Running Command

cd /home/daytona/workspace/ecg-pptx && \ sed -i 's/(row as string\[\])/row/g' build.js && \ sed -i 's/(items as typeof arrhythmias)/items/g' build.js && \ sed -i 's/xBase as number/xBase/g' build.js && \ sed -i 's/col as string/col/g' build.js && \ sed -i 's/name as string/name/g' build.js && \ sed -i 's/desc as string/desc/g' build.js && \ sed -i 's/ecg as string/ecg/g' build.js && \ sed -i 's/dx as string/dx/g' build.js && \ sed -i 's/(items as typeof clues)/items/g' build.js && \ echo "Done"

Running Command

cd /home/daytona/workspace/ecg-pptx && python3 -c " content = open('build.js').read() replacements = [ ('(row as string[]).map', 'row.map'), ('(items as typeof arrhythmias).forEach', 'items.forEach'), ('xBase as number', 'xBase'), ('col as string', 'col'), ('name as string', 'name'), ('desc as string', 'desc'), ('ecg as string', 'ecg'), ('dx as string', 'dx'), ('(items as typeof clues).forEach', 'items.forEach'), ] for old, new in replacements: content = content.replace(old, new) open('build.js', 'w').write(content) print('Done') "

Running Command

cd /home/daytona/workspace/ecg-pptx && node build.js 2>&1

Running Command

cd /home/daytona/workspace/ecg-pptx && python3 -c " content = open('build.js').read() # Replace the fetchImages function and usage with one-at-a-time fetching old = '''function fetchImages(...urls) { const result = execSync( \`node /home/daytona/skills/shared/scripts/fetch_images.js \${urls.map(u => \`\"\${u}\"\`).join(\" \")}\` ).toString(); return JSON.parse(result); } // Download key ECG images used throughout the deck const imgUrls = [ \"https://cdn.orris.care/cdss_images/ef815eeb06c673b405e3c7f9112d1e9ff6fbea96a00a2723b233d384156386bd.png\", // ECG waveform diagram \"https://cdn.orris.care/cdss_images/ed3e36266afd563652d7495682c022c3508452257126640a6ab3375b0b0a7e46.png\", // Conduction system \"https://cdn.orris.care/cdss_images/a768a511d3107d6bff69c3e8cf7b50c4485d458be34be6234f7fc6d4ca4fc3ec.png\", // Cardiac cycle ]; console.log(\"Downloading images...\"); const imgs = fetchImages(...imgUrls); const ecgWaveImg = imgs[0].base64; // waveform const condSysImg = imgs[1].base64; // conduction system const cardCycImg = imgs[2].base64; // cardiac cycle''' new_code = '''function fetchOneImage(url) { const result = execSync( \`node /home/daytona/skills/shared/scripts/fetch_images.js \"\${url}\"\`, { maxBuffer: 20 * 1024 * 1024 } ).toString(); return JSON.parse(result)[0].base64; } // Download key ECG images used throughout the deck console.log(\"Downloading images...\"); const ecgWaveImg = fetchOneImage(\"https://cdn.orris.care/cdss_images/ef815eeb06c673b405e3c7f9112d1e9ff6fbea96a00a2723b223d384156386bd.png\"); const condSysImg = fetchOneImage(\"https://cdn.orris.care/cdss_images/ed3e36266afd563652d7495682c022c3508452257126640a6ab3375b0b0a7e46.png\"); const cardCycImg = fetchOneImage(\"https://cdn.orris.care/cdss_images/a768a511d3107d6bff69c3e8cf7b50c4485d458be34be6234f7fc6d4ca4fc3ec.png\");''' content = content.replace(old, new_code) open('build.js', 'w').write(content) print('Done, checking...') " && node -e "require('./build.js')" 2>&1 | head -5 || true

Reading File
Editing File

~/ecg-pptx/build.js

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-pptx/build.js'
Running Command

cd /home/daytona/workspace/ecg-pptx && node build.js 2>&1

Running Command

node -e "const p = require('pptxgenjs'); const pr = new p(); console.log(JSON.stringify(Object.keys(pr.ShapeType || pr.shapes || {})).slice(0,400))"

Running Command

node -e "const p = require('pptxgenjs'); const pr = new p(); const keys = Object.keys(pr.ShapeType || {}); console.log(keys.filter(k => /ellipse|oval|circle|rect|round/i.test(k)).join(', '))"

Running Command

cd /home/daytona/workspace/ecg-pptx && python3 -c " content = open('build.js').read() # Fix shape type references content = content.replace('pres.shapes.ELLIPSE', 'pres.ShapeType.ellipse') content = content.replace('pres.shapes.RECTANGLE', 'pres.ShapeType.rect') content = content.replace('pres.shapes.ROUNDED_RECTANGLE', 'pres.ShapeType.roundRect') content = content.replace('pres.shapes.LINE', 'pres.ShapeType.line') open('build.js', 'w').write(content) print('Fixed shape types') "

Running Command

cd /home/daytona/workspace/ecg-pptx && node build.js 2>&1

Model call limits exceeded: run limit (20/20)
This is a shared conversation. Sign in to Orris to start your own chat.