~/ortho-ddx-pptx/create_pptx.js
const pptxgen = require("pptxgenjs");
const pres = new pptxgen();
pres.layout = "LAYOUT_WIDE"; // 13.3 x 7.5 inches
pres.title = "Differential Diagnosis Algorithms: Knee, Hip & Back Pain";
pres.author = "Orthopaedic Clinical Reference";
// ─── COLOUR PALETTE ────────────────────────────────────────────────
const C = {
navy: "0D2B4E", // dominant dark
teal: "1A7E8F", // supporting
orange: "E8622A", // accent / red flags
amber: "F2A83B", // warning yellow
green: "2A8C5A", // positive / reassuring
white: "FFFFFF",
offWhite: "F4F6F8",
lightGrey: "DCE2EA",
midGrey: "7F9BB5",
darkText: "1A2B3C",
};
// ─── HELPER: section divider badge ──────────────────────────────────
function badge(slide, label, color, x, y, w = 1.8, h = 0.38) {
slide.addShape(pres.ShapeType.roundRect, {
x, y, w, h,
fill: { color },
rectRadius: 0.06,
line: { color, width: 0 },
});
slide.addText(label, {
x, y, w, h,
fontSize: 11, bold: true, color: C.white,
align: "center", valign: "middle", margin: 0,
fontFace: "Calibri",
});
}
// ─── HELPER: flow box ───────────────────────────────────────────────
function flowBox(slide, text, x, y, w, h, fillColor, textColor = C.white, fontSize = 11) {
slide.addShape(pres.ShapeType.roundRect, {
x, y, w, h,
fill: { color: fillColor },
line: { color: fillColor, width: 0 },
rectRadius: 0.08,
shadow: { type: "outer", color: "000000", blur: 4, offset: 1, angle: 135, opacity: 0.12 },
});
slide.addText(text, {
x, y, w, h,
fontSize, bold: false, color: textColor,
align: "center", valign: "middle",
fontFace: "Calibri", margin: 4,
});
}
// ─── HELPER: arrow ──────────────────────────────────────────────────
function arrow(slide, x1, y1, x2, y2, color = C.midGrey) {
slide.addShape(pres.ShapeType.line, {
x: x1, y: y1, w: x2 - x1, h: y2 - y1,
line: { color, width: 1.5, endArrowType: "triangle" },
});
}
// ─── HELPER: down arrow (vertical) ──────────────────────────────────
function downArrow(slide, x, y, len = 0.25, color = C.midGrey) {
slide.addShape(pres.ShapeType.line, {
x, y, w: 0, h: len,
line: { color, width: 1.5, endArrowType: "triangle" },
});
}
// ─── HELPER: right arrow (horizontal) ───────────────────────────────
function rightArrow(slide, x, y, len = 0.3, color = C.midGrey) {
slide.addShape(pres.ShapeType.line, {
x, y, w: len, h: 0,
line: { color, width: 1.5, endArrowType: "triangle" },
});
}
// ─── HELPER: section header strip ───────────────────────────────────
function headerStrip(slide, title, subtitle) {
slide.addShape(pres.ShapeType.rect, {
x: 0, y: 0, w: 13.3, h: 1.15,
fill: { color: C.navy },
});
slide.addShape(pres.ShapeType.rect, {
x: 0, y: 1.15, w: 13.3, h: 0.07,
fill: { color: C.teal },
});
slide.addText(title, {
x: 0.4, y: 0.08, w: 9, h: 0.6,
fontSize: 26, bold: true, color: C.white,
fontFace: "Calibri", margin: 0,
});
if (subtitle) {
slide.addText(subtitle, {
x: 0.4, y: 0.68, w: 9, h: 0.4,
fontSize: 13, color: C.midGrey,
fontFace: "Calibri", margin: 0,
});
}
}
// ─── HELPER: red flag box ────────────────────────────────────────────
function redFlagBox(slide, items, x, y, w = 3.9) {
const h = 0.36 + items.length * 0.32;
slide.addShape(pres.ShapeType.roundRect, {
x, y, w, h,
fill: { color: "FFF0EC" },
line: { color: C.orange, width: 1.5 },
rectRadius: 0.08,
});
slide.addText("🚩 RED FLAGS", {
x, y: y + 0.03, w, h: 0.32,
fontSize: 11, bold: true, color: C.orange,
align: "center", fontFace: "Calibri", margin: 0,
});
const bullets = items.map((t, i) => ({
text: t,
options: { bullet: { type: "bullet" }, breakLine: i < items.length - 1 },
}));
slide.addText(bullets, {
x: x + 0.15, y: y + 0.36, w: w - 0.3, h: items.length * 0.32,
fontSize: 9.5, color: C.darkText, fontFace: "Calibri",
valign: "top",
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 1 – TITLE
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.navy };
// Decorative rectangles
s.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 0.35, h: 7.5, fill: { color: C.teal } });
s.addShape(pres.ShapeType.rect, { x: 0.35, y: 0, w: 0.12, h: 7.5, fill: { color: C.orange } });
s.addShape(pres.ShapeType.rect, { x: 0, y: 5.5, w: 13.3, h: 2.0, fill: { color: "0A2340" } });
s.addText("Differential Diagnosis", {
x: 0.8, y: 1.1, w: 11, h: 0.85,
fontSize: 40, bold: true, color: C.white, fontFace: "Calibri",
charSpacing: 1,
});
s.addText("Algorithms for Orthopaedic Pain", {
x: 0.8, y: 1.9, w: 11, h: 0.75,
fontSize: 34, bold: false, color: C.teal, fontFace: "Calibri",
});
// Three topic badges
const topics = [
{ label: "KNEE PAIN", color: C.teal },
{ label: "HIP PAIN", color: C.orange },
{ label: "BACK PAIN", color: C.green },
];
topics.forEach((t, i) => {
s.addShape(pres.ShapeType.roundRect, {
x: 0.8 + i * 3.5, y: 3.0, w: 3.0, h: 0.55,
fill: { color: t.color }, rectRadius: 0.1,
});
s.addText(t.label, {
x: 0.8 + i * 3.5, y: 3.0, w: 3.0, h: 0.55,
fontSize: 16, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
});
s.addText("Systematic clinical approach · Key differentials · Red flags · Investigation pathways", {
x: 0.8, y: 3.9, w: 11, h: 0.45,
fontSize: 13, color: C.lightGrey, fontFace: "Calibri",
});
s.addText("Sources: Harrison's 22E · Goldman-Cecil Medicine · Campbell's Operative Orthopaedics 15E · Tintinalli's Emergency Medicine · S Das Clinical Surgery 13E", {
x: 0.5, y: 5.85, w: 12.3, h: 0.5,
fontSize: 8.5, color: C.midGrey, fontFace: "Calibri", align: "center",
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 2 – OVERVIEW: APPROACH TO MUSCULOSKELETAL PAIN
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Systematic Approach to Musculoskeletal Pain", "Common framework applicable to knee, hip, and back complaints");
// Step boxes across the top
const steps = [
{ n: "1", title: "HISTORY", detail: "SOCRATES\nOnset · Character\nRadiation · Timing\nMechanical vs. inflammatory\nRed flag screening" },
{ n: "2", title: "EXAMINATION", detail: "Inspection · Palpation\nRange of motion\nSpecial tests\nNeurological screen\nGait & posture" },
{ n: "3", title: "RED FLAGS", detail: "Night pain\nWeight loss / fever\nNeurological deficit\nBladder/bowel dysfunction\nHistory of cancer" },
{ n: "4", title: "INVESTIGATE", detail: "X-ray (weight-bearing)\nMRI (soft tissue / neural)\nBlood tests: ESR, CRP\nBone scan · EMG/NCS" },
{ n: "5", title: "DIAGNOSE", detail: "Mechanical\nInflammatory\nInfective\nNeoplastic\nReferred" },
];
const bw = 2.2;
const gap = 0.35;
const startX = 0.35;
const y0 = 1.5;
steps.forEach((st, i) => {
const x = startX + i * (bw + gap);
const isRed = i === 2;
const fillC = isRed ? C.orange : C.navy;
// Number circle
s.addShape(pres.ShapeType.ellipse, {
x: x + bw / 2 - 0.25, y: y0 - 0.3, w: 0.5, h: 0.5,
fill: { color: isRed ? C.orange : C.teal }, line: { color: "FFFFFF", width: 2 },
});
s.addText(st.n, {
x: x + bw / 2 - 0.25, y: y0 - 0.3, w: 0.5, h: 0.5,
fontSize: 14, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
// Card
s.addShape(pres.ShapeType.roundRect, {
x, y: y0 + 0.3, w: bw, h: 1.0,
fill: { color: fillC }, rectRadius: 0.08,
});
s.addText(st.title, {
x, y: y0 + 0.3, w: bw, h: 0.38,
fontSize: 13, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 4,
});
s.addShape(pres.ShapeType.rect, {
x, y: y0 + 0.68, w: bw, h: 0.62,
fill: { color: "E8EEF5" },
});
s.addText(st.detail, {
x: x + 0.05, y: y0 + 0.7, w: bw - 0.1, h: 0.6,
fontSize: 8.5, color: C.darkText, fontFace: "Calibri",
valign: "top",
});
// Arrow between cards
if (i < steps.length - 1) {
rightArrow(s, x + bw + 0.02, y0 + 0.82, gap - 0.04, C.teal);
}
});
// Mechanical vs inflammatory table
s.addShape(pres.ShapeType.roundRect, {
x: 0.35, y: 3.15, w: 12.6, h: 3.88,
fill: { color: C.white }, line: { color: C.lightGrey, width: 1 }, rectRadius: 0.1,
shadow: { type: "outer", color: "000000", blur: 5, offset: 1, angle: 135, opacity: 0.08 },
});
s.addText("Mechanical vs. Inflammatory Pain — Key Distinguishing Features", {
x: 0.5, y: 3.2, w: 12, h: 0.38,
fontSize: 13, bold: true, color: C.navy, fontFace: "Calibri", margin: 4,
});
const tableData = [
[
{ text: "Feature", options: { bold: true, fill: { color: C.navy }, color: C.white, align: "center" } },
{ text: "Mechanical", options: { bold: true, fill: { color: C.teal }, color: C.white, align: "center" } },
{ text: "Inflammatory", options: { bold: true, fill: { color: C.orange }, color: C.white, align: "center" } },
{ text: "Infective", options: { bold: true, fill: { color: "6B3E9E" }, color: C.white, align: "center" } },
{ text: "Neoplastic", options: { bold: true, fill: { color: "333333" }, color: C.white, align: "center" } },
],
["Morning stiffness", "< 30 minutes", "> 1 hour", "Variable", "Absent"],
["Night pain", "Late stage only", "Often present", "Present + fever", "Classic symptom"],
["Response to rest", "Improves", "Variable", "No improvement", "No improvement"],
["Systemic symptoms", "Absent", "Fatigue, malaise", "Fever, rigors", "Weight loss, fatigue"],
["Onset pattern", "Acute / gradual", "Insidious / episodic", "Acute / subacute", "Progressive, insidious"],
["Blood markers", "Normal", "↑ ESR, CRP, RF/ACPA", "↑ WBC, ESR, CRP", "↑ ESR, Ca2+, ALP"],
];
s.addTable(tableData, {
x: 0.4, y: 3.62, w: 12.5, h: 3.3,
fontFace: "Calibri",
fontSize: 10,
border: { pt: 0.5, color: C.lightGrey },
rowH: 0.38,
align: "center",
valign: "middle",
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 3 – KNEE PAIN ALGORITHM (PART 1: LOCATION-BASED)
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Knee Pain — Differential Diagnosis Algorithm", "Step 1: Localise pain · Step 2: Identify mechanism · Step 3: Classify");
// Central "KNEE PAIN" node
const cx = 6.5, cy = 3.3;
s.addShape(pres.ShapeType.ellipse, {
x: cx - 1.05, y: cy - 0.45, w: 2.1, h: 0.9,
fill: { color: C.navy }, line: { color: C.teal, width: 2 },
});
s.addText("KNEE PAIN", {
x: cx - 1.05, y: cy - 0.45, w: 2.1, h: 0.9,
fontSize: 14, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
// ── Branches: 5 regions ──
const branches = [
{
dir: "top",
label: "ANTERIOR",
color: C.teal,
dx: 0, dy: -2.2, bw: 3.2, bh: 2.0,
items: [
"Patellofemoral syndrome (OA)",
"Patellar tendinopathy / tendon tear",
"Prepatellar bursitis ('housemaid's knee')",
"Osgood-Schlatter (adolescent, tibial tubercle)",
"Quadriceps tendon tear (elderly, sudden)",
"Infrapatellar bursitis",
],
},
{
dir: "right",
label: "LATERAL",
color: C.teal,
dx: 2.5, dy: -0.5, bw: 3.5, bh: 1.6,
items: [
"Lateral meniscus tear",
"IT band syndrome (runners)",
"LCL sprain / tear",
"Lateral tibial plateau fracture",
"Common peroneal nerve injury",
],
},
{
dir: "bottom-right",
label: "POSTERIOR",
color: C.teal,
dx: 1.5, dy: 1.6, bw: 3.1, bh: 1.3,
items: [
"Baker's cyst (popliteal cyst)",
"Posterior capsule sprain",
"PCL tear",
"DVT (exclude!)",
],
},
{
dir: "bottom-left",
label: "DIFFUSE / INTRA-ARTICULAR",
color: C.orange,
dx: -4.8, dy: 1.4, bw: 3.6, bh: 1.65,
items: [
"Osteoarthritis (commonest)",
"Rheumatoid arthritis",
"Crystal arthropathy (gout/pseudogout)",
"Septic arthritis (EMERGENCY)",
"Haemarthrosis (ACL rupture, fracture)",
],
},
{
dir: "left",
label: "MEDIAL",
color: C.teal,
dx: -4.5, dy: -0.6, bw: 3.5, bh: 1.6,
items: [
"Medial meniscus tear",
"MCL sprain / tear",
"Pes anserine bursitis",
"Medial tibial plateau fracture",
"Medial plica syndrome",
],
},
];
branches.forEach(b => {
const bx = cx + b.dx;
const by = cy + b.dy;
// Arrow from centre to box edge
const arrowStartX = cx;
const arrowStartY = cy;
const arrowEndX = bx + b.bw / 2;
const arrowEndY = by + b.bh / 2;
s.addShape(pres.ShapeType.line, {
x: Math.min(arrowStartX, arrowEndX),
y: Math.min(arrowStartY, arrowEndY),
w: Math.abs(arrowEndX - arrowStartX),
h: Math.abs(arrowEndY - arrowStartY),
line: { color: C.midGrey, width: 1, endArrowType: "triangle" },
flipH: arrowStartX > arrowEndX,
flipV: arrowStartY > arrowEndY,
});
// Region header
s.addShape(pres.ShapeType.roundRect, {
x: bx, y: by, w: b.bw, h: 0.35,
fill: { color: b.color }, rectRadius: 0.06,
});
s.addText(b.label, {
x: bx, y: by, w: b.bw, h: 0.35,
fontSize: 10, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
// Items
s.addShape(pres.ShapeType.roundRect, {
x: bx, y: by + 0.35, w: b.bw, h: b.bh - 0.35,
fill: { color: C.white }, line: { color: b.color, width: 1 }, rectRadius: 0.06,
});
const txtItems = b.items.map((t, i) => ({
text: t,
options: { bullet: { type: "bullet" }, breakLine: i < b.items.length - 1, fontSize: 9 },
}));
s.addText(txtItems, {
x: bx + 0.1, y: by + 0.4, w: b.bw - 0.2, h: b.bh - 0.48,
fontFace: "Calibri", color: C.darkText, valign: "top", fontSize: 9,
});
});
// Footnote
s.addText("* Always examine the HIP — hip pathology (OA, fracture) commonly presents as knee pain | Immediate effusion (< 2h) = haemarthrosis (ACL rupture until proven otherwise)", {
x: 0.35, y: 6.95, w: 12.6, h: 0.35,
fontSize: 8, color: C.midGrey, fontFace: "Calibri", italic: true,
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 4 – KNEE PAIN DECISION FLOWCHART
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Knee Pain — Clinical Decision Flowchart", "Structured stepwise diagnostic approach");
// Start node
flowBox(s, "PATIENT WITH KNEE PAIN", 4.3, 1.35, 4.7, 0.52, C.navy, C.white, 13);
downArrow(s, 6.65, 1.87, 0.28);
// Q1
flowBox(s, "Trauma / acute injury?", 4.8, 2.15, 3.7, 0.45, C.teal, C.white, 11);
// YES branch
s.addShape(pres.ShapeType.line, { x: 6.65, y: 2.6, w: 0, h: 0.22, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "Immediate swelling\n(< 2 hours)?", 5.2, 2.82, 2.9, 0.55, "2471A3", C.white, 10);
// YES from immediate swelling
s.addShape(pres.ShapeType.line, { x: 5.2, y: 3.09, w: -0.25, h: 0, line: { color: C.green, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "YES → Haemarthrosis\n• ACL rupture\n• Osteochondral fracture\n• Patellar dislocation", 2.1, 2.78, 2.8, 0.72, C.orange, C.white, 9);
// NO from immediate swelling
s.addShape(pres.ShapeType.line, { x: 8.1, y: 3.09, w: 0.25, h: 0, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "NO → Delayed swelling\n(12–24 h)\n• Meniscal tear\n• Ligament sprain\n• Contusion", 8.35, 2.78, 2.9, 0.72, C.teal, C.white, 9);
// Q2 — Trauma NO
s.addShape(pres.ShapeType.line, { x: 8.5, y: 2.37, w: 0.25, h: 0, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "NO trauma:\nInflammatory symptoms?\n(fever, warm, erythema, systemic)", 8.75, 2.1, 4.1, 0.6, "2471A3", C.white, 9.5);
// YES inflammatory
s.addShape(pres.ShapeType.line, { x: 10.8, y: 2.7, w: 0, h: 0.22, line: { color: C.orange, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "HOT SWOLLEN JOINT\nSeptic arthritis (EMERGENCY)\nGout / Pseudogout\nReactive arthritis\nRA flare\n⚑ Joint aspiration indicated", 9.2, 2.92, 3.2, 1.05, C.orange, C.white, 9);
// NO inflammatory → chronic
s.addShape(pres.ShapeType.line, { x: 4.8, y: 2.37, w: -0.25, h: 0, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "NO trauma, NO inflammation:\nLocation of pain?", 1.3, 2.1, 3.25, 0.55, "2471A3", C.white, 10);
// Location branches
const locs = [
{ label: "Anterior", dx: 0.2, dx2: 0.2, diag: "Patellofemoral OA\nPatellar tendinopathy\nBursitis" },
{ label: "Medial", dx: 1.55, dx2: 1.55, diag: "Medial meniscus tear\nMCL injury\nPes anserine bursitis" },
{ label: "Lateral", dx: 2.9, dx2: 2.9, diag: "Lateral meniscus tear\nIT band syndrome\nLCL injury" },
];
locs.forEach(l => {
s.addShape(pres.ShapeType.line, { x: 1.3 + l.dx + 0.5, y: 2.65, w: 0, h: 0.25, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, l.label, 0.85 + l.dx, 2.9, 1.1, 0.36, C.green, C.white, 9.5);
s.addShape(pres.ShapeType.line, { x: 1.4 + l.dx, y: 3.26, w: 0, h: 0.22, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, l.diag, 0.7 + l.dx2, 3.48, 1.45, 0.7, C.white, C.darkText, 8);
// border
s.addShape(pres.ShapeType.roundRect, { x: 0.7 + l.dx2, y: 3.48, w: 1.45, h: 0.7, fill: { color: C.white }, line: { color: C.green, width: 1 }, rectRadius: 0.06 });
});
// Mechanical symptoms row
s.addShape(pres.ShapeType.line, { x: 2.92, y: 3.26, w: 0, h: 0.6, line: { color: C.midGrey, width: 1.5 } });
s.addShape(pres.ShapeType.line, { x: 2.92, y: 3.86, w: 0.6, h: 0, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "Mechanical symptoms?\n(locking, giving way, click)", 3.52, 3.68, 3.0, 0.52, "2471A3", C.white, 9.5);
s.addShape(pres.ShapeType.line, { x: 6.52, y: 3.94, w: 0.28, h: 0, line: { color: C.orange, width: 1.5, endArrowType: "triangle" } });
flowBox(s, "Locking → Meniscal (bucket-handle)\nGiving way → ACL / PF instability\nClick → Meniscal / Plica", 6.8, 3.68, 3.55, 0.52, C.teal, C.white, 9);
// Neurological / referred
s.addShape(pres.ShapeType.rect, { x: 0.35, y: 4.55, w: 12.6, h: 0.04, fill: { color: C.lightGrey } });
s.addText("⚠ Always check: Hip exam (referred pain) · Neurovascular screen (DVT, common peroneal nerve) · BMI & gait for OA workup", {
x: 0.4, y: 4.65, w: 12.5, h: 0.38,
fontSize: 9.5, color: C.orange, bold: true, fontFace: "Calibri",
});
// Investigation guide
s.addShape(pres.ShapeType.roundRect, {
x: 0.35, y: 5.1, w: 12.6, h: 2.15,
fill: { color: C.white }, line: { color: C.lightGrey, width: 1 }, rectRadius: 0.1,
});
s.addText("Investigation Pathway for Knee Pain", {
x: 0.5, y: 5.12, w: 8, h: 0.32,
fontSize: 11, bold: true, color: C.navy, fontFace: "Calibri", margin: 0,
});
const invCols = [
{ title: "FIRST LINE", color: C.green, items: ["Weight-bearing X-ray (AP, lateral, skyline)", "Inflammatory markers (ESR, CRP, WBC)", "Uric acid (if gout suspected)", "Joint aspiration (hot joint)"] },
{ title: "SECOND LINE", color: C.teal, items: ["MRI knee (meniscus, ligament, cartilage)", "Ultrasound (Baker's cyst, bursitis, tendon)", "DECT (gout tophus)"] },
{ title: "SPECIAL CASES", color: C.orange, items: ["Bone scan (stress fracture, AVN, occult)", "CT (complex fracture, tibial plateau)", "Synovial fluid microscopy (crystals, culture)"] },
];
invCols.forEach((col, i) => {
const cx2 = 0.45 + i * 4.3;
s.addShape(pres.ShapeType.roundRect, { x: cx2, y: 5.48, w: 4.1, h: 0.32, fill: { color: col.color }, rectRadius: 0.05 });
s.addText(col.title, { x: cx2, y: 5.48, w: 4.1, h: 0.32, fontSize: 10, bold: true, color: C.white, align: "center", valign: "middle", fontFace: "Calibri", margin: 0 });
const buls = col.items.map((t, idx) => ({ text: t, options: { bullet: { type: "bullet" }, breakLine: idx < col.items.length - 1 } }));
s.addText(buls, { x: cx2 + 0.08, y: 5.82, w: 3.95, h: 1.38, fontSize: 9, color: C.darkText, fontFace: "Calibri", valign: "top" });
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 5 – HIP PAIN ALGORITHM
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Hip Pain — Differential Diagnosis Algorithm", "Location of pain is the primary diagnostic guide");
// Central node
flowBox(s, "HIP PAIN", 5.85, 1.55, 1.6, 0.5, C.navy, C.white, 14);
// 4 primary zones
const zones = [
{
label: "GROIN / ANTERIOR HIP",
color: C.teal,
x: 0.3, y: 1.45, w: 4.5, h: 2.35,
items: [
{ t: "Hip OA (commonest — insidious, elderly)", b: true },
{ t: "Femoral neck fracture (elderly, fall, cannot WB)", b: true },
{ t: "AVN of femoral head (steroids, EtOH, SCD)", b: false },
{ t: "Labral tear (young, athletic, catching)", b: false },
{ t: "Psoas bursitis / tendinopathy", b: false },
{ t: "Hip joint effusion (septic arthritis)", b: false },
{ t: "Femoral stress fracture (young runner)", b: false },
],
arrow: { from: "right", targetX: 5.85, targetY: 1.8 },
},
{
label: "LATERAL HIP / GREATER TROCHANTER",
color: C.green,
x: 0.3, y: 4.1, w: 4.5, h: 2.05,
items: [
{ t: "Trochanteric bursitis / gluteus medius tendinopathy (most common lateral hip pain)", b: false },
{ t: "IT band syndrome", b: false },
{ t: "Snapping hip (coxa saltans)", b: false },
{ t: "L4-L5 referred pain (lateral thigh)", b: false },
],
arrow: null,
},
{
label: "POSTERIOR / BUTTOCK",
color: C.amber,
x: 8.5, y: 1.45, w: 4.5, h: 2.1,
items: [
{ t: "Piriformis syndrome (buttock, sciatica-like)", b: false },
{ t: "SI joint dysfunction / sacroiliitis", b: false },
{ t: "L5-S1 radiculopathy (referred)", b: false },
{ t: "Ischiogluteal bursitis (sitting pain)", b: false },
{ t: "Proximal hamstring tear", b: false },
],
arrow: { from: "left", targetX: 7.45, targetY: 1.8 },
},
{
label: "DIFFUSE / SYSTEMIC",
color: C.orange,
x: 8.5, y: 3.85, w: 4.5, h: 2.3,
items: [
{ t: "Inflammatory arthritis (RA, AS, PsA)", b: false },
{ t: "Crystal arthropathy (rare in hip)", b: false },
{ t: "Septic arthritis (HOT, cannot WB — EMERGENCY)", b: true },
{ t: "Malignancy / bone metastases (night pain, weight loss)", b: true },
{ t: "Paget's disease (elderly, deformity)", b: false },
{ t: "Transient osteoporosis of hip (pregnant, MRI)", b: false },
],
arrow: null,
},
];
zones.forEach(z => {
s.addShape(pres.ShapeType.roundRect, {
x: z.x, y: z.y, w: z.w, h: 0.35,
fill: { color: z.color }, rectRadius: 0.06,
});
s.addText(z.label, {
x: z.x, y: z.y, w: z.w, h: 0.35,
fontSize: 9.5, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
s.addShape(pres.ShapeType.roundRect, {
x: z.x, y: z.y + 0.35, w: z.w, h: z.h - 0.35,
fill: { color: C.white }, line: { color: z.color, width: 1 }, rectRadius: 0.06,
});
const buls = z.items.map((t, i) => ({
text: t.t,
options: {
bullet: { type: "bullet" },
breakLine: i < z.items.length - 1,
bold: t.b,
color: t.b ? C.orange : C.darkText,
},
}));
s.addText(buls, {
x: z.x + 0.1, y: z.y + 0.4, w: z.w - 0.2, h: z.h - 0.52,
fontSize: 9, fontFace: "Calibri", valign: "top",
});
});
// Age-based triage box (centre bottom)
s.addShape(pres.ShapeType.roundRect, {
x: 4.8, y: 2.25, w: 3.7, h: 3.75,
fill: { color: "EEF3F8" }, line: { color: C.navy, width: 1.5 }, rectRadius: 0.1,
});
s.addText("AGE-BASED TRIAGE", {
x: 4.8, y: 2.25, w: 3.7, h: 0.38,
fontSize: 11, bold: true, color: C.navy, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
const ageGroups = [
{ age: "Child / Adolescent", color: C.teal, diag: "Perthes disease, SCFE, transient synovitis, developmental dysplasia" },
{ age: "Young Adult (20–40)", color: C.green, diag: "Labral tear, AVN (steroids/EtOH), stress fracture, FAI, athletic injury" },
{ age: "Middle Age (40–60)", color: C.amber, diag: "OA (early), trochanteric bursitis, piriformis syndrome, RA" },
{ age: "Elderly (> 60)", color: C.orange, diag: "OA (late), femoral neck fracture, AVN, malignancy, Paget's" },
];
ageGroups.forEach((ag, i) => {
const ay = 2.7 + i * 0.82;
s.addShape(pres.ShapeType.roundRect, { x: 4.9, y: ay, w: 3.5, h: 0.3, fill: { color: ag.color }, rectRadius: 0.05 });
s.addText(ag.age, { x: 4.9, y: ay, w: 3.5, h: 0.3, fontSize: 9.5, bold: true, color: C.white, align: "center", valign: "middle", fontFace: "Calibri", margin: 0 });
s.addText(ag.diag, { x: 4.95, y: ay + 0.3, w: 3.4, h: 0.48, fontSize: 8, color: C.darkText, fontFace: "Calibri", valign: "top" });
});
// footnote
s.addText("FABER test: hip / SI joint pain | FADIR test: FAI / labral tear | Trendelenburg: abductor weakness | Leg length: measure ASIS → medial malleolus", {
x: 0.35, y: 6.95, w: 12.6, h: 0.35,
fontSize: 8, color: C.midGrey, fontFace: "Calibri", italic: true,
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 6 – BACK PAIN ALGORITHM (TRIAGE)
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Back Pain — Triage Algorithm", "First step: Rule out serious pathology before considering mechanical aetiology");
// Top flow: triage
flowBox(s, "BACK PAIN", 5.65, 1.38, 2.0, 0.5, C.navy, C.white, 14);
downArrow(s, 6.65, 1.88, 0.25);
// Diamond: Red flags?
s.addShape(pres.ShapeType.rect, {
x: 5.6, y: 2.13, w: 2.1, h: 0.6,
fill: { color: C.orange }, line: { color: C.orange, width: 0 },
});
s.addText("RED FLAGS\npresent?", {
x: 5.6, y: 2.13, w: 2.1, h: 0.6,
fontSize: 10, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
// YES → serious
s.addShape(pres.ShapeType.line, { x: 7.7, y: 2.43, w: 0.6, h: 0, line: { color: C.orange, width: 2, endArrowType: "triangle" } });
s.addText("YES", { x: 7.7, y: 2.27, w: 0.6, h: 0.3, fontSize: 9, bold: true, color: C.orange, fontFace: "Calibri", align: "center" });
flowBox(s, "⚑ SERIOUS PATHOLOGY\n→ Urgent investigation", 8.3, 2.18, 3.2, 0.5, C.orange, C.white, 10);
// NO → duration?
s.addShape(pres.ShapeType.line, { x: 6.65, y: 2.73, w: 0, h: 0.25, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
s.addText("NO", { x: 6.7, y: 2.73, w: 0.4, h: 0.25, fontSize: 9, bold: true, color: C.green, fontFace: "Calibri" });
flowBox(s, "Duration of pain?", 5.65, 2.98, 2.0, 0.45, "2471A3", C.white, 11);
// Three duration branches
const durs = [
{ label: "< 6 weeks\n(ACUTE)", color: C.green, x: 1.5, diag: "Acute muscle strain\nLigament sprain\nAcute disc herniation\nVertebral fracture (trauma)" },
{ label: "6–12 weeks\n(SUBACUTE)", color: C.amber, x: 5.2, diag: "Recovering disc herniation\nFacet syndrome\nSI joint dysfunction\nInitiate active rehabilitation" },
{ label: "> 12 weeks\n(CHRONIC)", color: C.orange, x: 8.9, diag: "Chronic disc disease\nSpinal stenosis\nFacet arthropathy\nChronification / central sensitisation\nPsychosocial factors (yellow flags)" },
];
durs.forEach((d, i) => {
const mx = d.x + 1.8;
s.addShape(pres.ShapeType.line, {
x: Math.min(6.65, mx), y: 3.2,
w: Math.abs(6.65 - mx), h: 0,
line: { color: C.midGrey, width: 1 },
});
s.addShape(pres.ShapeType.line, { x: mx, y: 3.2, w: 0, h: 0.25, line: { color: C.midGrey, width: 1.5, endArrowType: "triangle" } });
flowBox(s, d.label, d.x, 3.45, 3.6, 0.5, d.color, C.white, 10);
s.addShape(pres.ShapeType.roundRect, {
x: d.x, y: 3.95, w: 3.6, h: 0.95,
fill: { color: C.white }, line: { color: d.color, width: 1 }, rectRadius: 0.08,
});
s.addText(d.diag, {
x: d.x + 0.1, y: 4.0, w: 3.4, h: 0.88,
fontSize: 9, color: C.darkText, fontFace: "Calibri", valign: "top",
});
});
// Red flags detailed box
s.addShape(pres.ShapeType.roundRect, {
x: 0.35, y: 5.05, w: 5.6, h: 2.22,
fill: { color: "FFF0EC" }, line: { color: C.orange, width: 1.5 }, rectRadius: 0.1,
});
s.addText("🚩 RED FLAGS — Must Rule Out", {
x: 0.45, y: 5.08, w: 5.4, h: 0.35,
fontSize: 11, bold: true, color: C.orange, fontFace: "Calibri", margin: 0,
});
const rfItems = [
"Age < 20 or > 50 years",
"History of malignancy",
"Unexplained weight loss / fever",
"Immunosuppression / IV drug use",
"Bladder or bowel dysfunction (CES!)",
"Bilateral neurological symptoms",
"Night pain / unrelenting pain",
"History of trauma (fracture risk)",
"Osteoporosis + minor trauma",
"Duration > 6 weeks without improvement",
];
const rfBuls = rfItems.map((t, i) => ({
text: t,
options: { bullet: { type: "bullet" }, breakLine: i < rfItems.length - 1 },
}));
s.addText(rfBuls, {
x: 0.45, y: 5.46, w: 5.3, h: 1.75,
fontSize: 9, color: C.darkText, fontFace: "Calibri", valign: "top",
});
// Serious pathology classification
s.addShape(pres.ShapeType.roundRect, {
x: 6.1, y: 5.05, w: 6.85, h: 2.22,
fill: { color: C.white }, line: { color: C.navy, width: 1 }, rectRadius: 0.1,
});
s.addText("Serious Conditions to Exclude", {
x: 6.2, y: 5.08, w: 6.6, h: 0.35,
fontSize: 11, bold: true, color: C.navy, fontFace: "Calibri", margin: 0,
});
const seriousCols = [
{ title: "NEURAL / SPINAL", items: ["Cauda equina syndrome", "Myelopathy / cord compression", "Epidural abscess / haematoma", "Spinal fracture"] },
{ title: "SYSTEMIC / REFERRED", items: ["Spinal metastases", "Multiple myeloma", "Aortic aneurysm (AAA)", "Pancreatitis / renal colic"] },
];
seriousCols.forEach((col, i) => {
const sx = 6.2 + i * 3.35;
s.addShape(pres.ShapeType.roundRect, { x: sx, y: 5.46, w: 3.2, h: 0.3, fill: { color: i === 0 ? C.orange : C.navy }, rectRadius: 0.04 });
s.addText(col.title, { x: sx, y: 5.46, w: 3.2, h: 0.3, fontSize: 9, bold: true, color: C.white, align: "center", valign: "middle", fontFace: "Calibri", margin: 0 });
const b = col.items.map((t, j) => ({ text: t, options: { bullet: { type: "bullet" }, breakLine: j < col.items.length - 1 } }));
s.addText(b, { x: sx + 0.05, y: 5.8, w: 3.1, h: 1.35, fontSize: 9, color: C.darkText, fontFace: "Calibri", valign: "top" });
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 7 – BACK PAIN: DETAILED DIAGNOSTIC CATEGORIES
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Back Pain — Diagnostic Categories & Key Features", "Mechanical (90%) vs. Non-mechanical (10%)");
const cats = [
{
title: "DISC HERNIATION (L4–L5, L5–S1)", color: C.teal, x: 0.3, y: 1.42, w: 3.85,
items: [
"Shooting / stabbing LBP + radiculopathy",
"Worse sitting, better lying / standing",
"L5: pain to dorsum foot / big toe",
"S1: pain to lateral foot / small toe",
"Worse with Valsalva / cough / sneeze",
"+ve SLR (sens. 85–91%; spec. 26–52%)",
"+ve crossed SLR (spec. 86–90%)",
],
},
{
title: "SPINAL STENOSIS", color: C.green, x: 4.35, y: 1.42, w: 3.85,
items: [
"Age > 60, bilateral leg pain",
"Neurogenic claudication",
"Worse: walking, standing, extension",
"Better: forward flexion, sitting, cycling",
"Mimics vascular claudication",
"Cycling test: can cycle (flexed = relief)",
"MRI: narrowed canal, ligamentum flavum hypertrophy",
],
},
{
title: "CAUDA EQUINA SYNDROME ⚑ EMERGENCY", color: C.orange, x: 8.4, y: 1.42, w: 4.55,
items: [
"Bilateral leg weakness / numbness",
"Saddle anaesthesia (perineum, inner thighs)",
"Bladder retention / overflow incontinence",
"Bowel incontinence / reduced anal tone",
"PVR > 100 mL = overflow incontinence",
"Cause: large central disc herniation (L4/5 or L5/S1)",
"→ Emergency MRI + same-day neurosurgery referral",
],
},
{
title: "FACET SYNDROME / SPONDYLOSIS", color: C.amber, x: 0.3, y: 4.12, w: 3.85,
items: [
"Axial LBP without radiculopathy",
"Worse with extension / rotation",
"Localised paraspinal tenderness",
"Morning stiffness improves with activity",
"X-ray: facet arthrosis, osteophytes",
"Facet injection: diagnostic + therapeutic",
],
},
{
title: "SI JOINT SYNDROME", color: "6B3E9E", x: 4.35, y: 4.12, w: 3.85,
items: [
"Unilateral buttock / posterior thigh pain",
"FABER test positive",
"Posterior SI compression positive",
"Pain radiating to groin",
"Common in pregnancy",
"Ankylosing spondylitis: bilateral sacroiliitis",
],
},
{
title: "NON-MECHANICAL / SYSTEMIC", color: C.navy, x: 8.4, y: 4.12, w: 4.55,
items: [
"Night pain: tumour, infection",
"Metastases: breast, prostate, lung, kidney, thyroid",
"Myeloma: lytic lesions (bone scan may miss!)",
"Discitis/osteomyelitis: fever + localised tenderness",
"AAA: bilateral flank/back pain, pulsatile mass",
"→ ESR, CRP, PSA, SPEP, MRI, bone scan",
],
},
];
cats.forEach(c => {
const bh = 2.4;
s.addShape(pres.ShapeType.roundRect, {
x: c.x, y: c.y, w: c.w, h: 0.38,
fill: { color: c.color }, rectRadius: 0.06,
});
s.addText(c.title, {
x: c.x, y: c.y, w: c.w, h: 0.38,
fontSize: 9.5, bold: true, color: C.white, align: "center", valign: "middle",
fontFace: "Calibri", margin: 0,
});
s.addShape(pres.ShapeType.roundRect, {
x: c.x, y: c.y + 0.38, w: c.w, h: bh - 0.38,
fill: { color: C.white }, line: { color: c.color, width: 1 }, rectRadius: 0.06,
});
const buls = c.items.map((t, i) => ({
text: t,
options: { bullet: { type: "bullet" }, breakLine: i < c.items.length - 1 },
}));
s.addText(buls, {
x: c.x + 0.1, y: c.y + 0.43, w: c.w - 0.2, h: bh - 0.5,
fontSize: 9, color: C.darkText, fontFace: "Calibri", valign: "top",
});
});
// LR table at bottom
s.addShape(pres.ShapeType.roundRect, {
x: 0.3, y: 6.72, w: 12.7, h: 0.55,
fill: { color: "EEF3F8" }, line: { color: C.navy, width: 1 }, rectRadius: 0.06,
});
s.addText([
{ text: "Likelihood Ratios for Cancer: ", options: { bold: true } },
{ text: "History of cancer LR+ 14.7 | Age >50 LR+ 2.7 | Weight loss LR+ 2.7 | Failure conservative Rx LR+ 3.0 | Nocturnal pain LR− 0.17 | ESR ≥50 LR+ 19.2", options: {} },
], {
x: 0.4, y: 6.75, w: 12.5, h: 0.48,
fontSize: 9, color: C.darkText, fontFace: "Calibri", valign: "middle",
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 8 – NERVE ROOT / DERMATOME REFERENCE
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Lumbar Radiculopathy — Nerve Root Reference Table", "Correlate history, dermatomal pain, motor signs, and reflexes");
const tableData = [
[
{ text: "Level", options: { bold: true, fill: { color: C.navy }, color: C.white } },
{ text: "Pain Distribution", options: { bold: true, fill: { color: C.navy }, color: C.white } },
{ text: "Sensory Loss", options: { bold: true, fill: { color: C.navy }, color: C.white } },
{ text: "Motor Weakness", options: { bold: true, fill: { color: C.navy }, color: C.white } },
{ text: "Reflex Change", options: { bold: true, fill: { color: C.navy }, color: C.white } },
{ text: "Provocation Test", options: { bold: true, fill: { color: C.navy }, color: C.white } },
],
[
{ text: "L2–L3", options: { bold: true, fill: { color: "EEF3F8" } } },
"Anterior thigh to knee",
"Anterior / medial thigh",
"Hip flexion, knee extension (quadriceps)",
"Knee jerk may be reduced",
"+ve Femoral stretch test",
],
[
{ text: "L4", options: { bold: true, fill: { color: "EEF3F8" } } },
"Medial leg to medial foot / great toe",
"Medial lower leg, dorsum foot",
"Tibialis anterior (dorsiflexion weakness)",
"Knee jerk reduced",
"+ve SLR, Femoral stretch",
],
[
{ text: "L5", options: { bold: true, fill: { color: "EEF3F8" } } },
"Lateral leg → dorsum foot → big toe",
"Dorsum of foot, 1st web space",
"EHL weakness (cannot extend big toe), foot drop risk",
"Usually preserved",
"+ve SLR (30–70°)",
],
[
{ text: "S1", options: { bold: true, fill: { color: "EEF3F8" } } },
"Posterior thigh/leg → lateral foot → small toe",
"Lateral foot, plantar",
"Peroneus longus/brevis (eversion), gastrocnemius",
"Ankle jerk reduced/absent",
"+ve SLR, +ve crossed SLR",
],
[
{ text: "S2–S4\n(Cauda equina)", options: { bold: true, fill: { color: "FFF0EC" }, color: C.orange } },
"Bilateral legs, perineum, saddle area",
"Saddle anaesthesia",
"Bilateral leg weakness, bladder/bowel dysfunction",
{ text: "Multiple reflexes absent", options: { color: C.orange, bold: true } },
{ text: "EMERGENCY — immediate MRI", options: { color: C.orange, bold: true } },
],
];
s.addTable(tableData, {
x: 0.3, y: 1.42, w: 12.7, h: 4.1,
fontFace: "Calibri", fontSize: 10,
border: { pt: 0.5, color: C.lightGrey },
rowH: 0.58,
align: "center",
valign: "middle",
autoPage: false,
});
// SLR accuracy box
s.addShape(pres.ShapeType.roundRect, {
x: 0.3, y: 5.72, w: 6.0, h: 1.55,
fill: { color: C.white }, line: { color: C.teal, width: 1.5 }, rectRadius: 0.1,
});
s.addText("Straight Leg Raise (SLR) — Accuracy", {
x: 0.4, y: 5.75, w: 5.8, h: 0.32,
fontSize: 11, bold: true, color: C.teal, fontFace: "Calibri", margin: 0,
});
s.addText([
{ text: "• SLR (ipsilateral): ", options: { bold: true } },
{ text: "Sensitivity 85–91%, Specificity 26–52% for disc herniation / sciatica\n", options: {} },
{ text: "• Crossed SLR: ", options: { bold: true } },
{ text: "Sensitivity 23–34%, Specificity 86–90% — high specificity for disc extrusion\n", options: {} },
{ text: "• Femoral stretch test: ", options: { bold: true } },
{ text: "L2, L3, L4 nerve roots (anterior thigh pain when knee flexed prone)", options: {} },
], {
x: 0.4, y: 6.1, w: 5.8, h: 1.1,
fontSize: 9.5, color: C.darkText, fontFace: "Calibri", valign: "top",
});
// Pain character box
s.addShape(pres.ShapeType.roundRect, {
x: 6.6, y: 5.72, w: 6.4, h: 1.55,
fill: { color: C.white }, line: { color: C.navy, width: 1.5 }, rectRadius: 0.1,
});
s.addText("Pain Features & Their Diagnostic Implications", {
x: 6.7, y: 5.75, w: 6.2, h: 0.32,
fontSize: 11, bold: true, color: C.navy, fontFace: "Calibri", margin: 0,
});
const painFeats = [
"Worse sitting + better lying → Disc herniation",
"Worse walking + better flexion → Spinal stenosis",
"Night pain waking from sleep → Tumour or infection",
"Valsalva-provoked pain → Disc herniation",
"Unrelenting + positional → AAA / systemic cause",
];
const pb = painFeats.map((t, i) => ({
text: t,
options: { bullet: { type: "bullet" }, breakLine: i < painFeats.length - 1 },
}));
s.addText(pb, {
x: 6.7, y: 6.1, w: 6.2, h: 1.1,
fontSize: 9.5, color: C.darkText, fontFace: "Calibri", valign: "top",
});
}
// ════════════════════════════════════════════════════════════════════
// SLIDE 9 – YELLOW FLAGS & SUMMARY
// ════════════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
s.background = { color: C.offWhite };
headerStrip(s, "Yellow Flags, Investigation Summary & Must-Not-Miss Diagnoses", "Psychosocial factors and surgical/urgent conditions");
// Yellow flags
s.addShape(pres.ShapeType.roundRect, {
x: 0.3, y: 1.42, w: 4.0, h: 2.7,
fill: { color: "FFFBEA" }, line: { color: C.amber, width: 1.5 }, rectRadius: 0.1,
});
s.addText("🟡 YELLOW FLAGS\n(Psychosocial — chronic pain risk)", {
x: 0.4, y: 1.45, w: 3.8, h: 0.5,
fontSize: 11, bold: true, color: C.amber, fontFace: "Calibri", margin: 0,
align: "center",
});
const yfItems = [
"Belief pain = disabling / catastrophic",
"Fear-avoidance of activity",
"Depression / anxiety / stress",
"Poor social/occupational support",
"Passive coping strategy",
"Previous compensation / litigation",
"Prolonged sick leave",
];
const yfB = yfItems.map((t, i) => ({ text: t, options: { bullet: { type: "bullet" }, breakLine: i < yfItems.length - 1 } }));
s.addText(yfB, { x: 0.4, y: 1.98, w: 3.7, h: 2.1, fontSize: 9.5, color: C.darkText, fontFace: "Calibri", valign: "top" });
// Must-not-miss table
const mntm = [
[
{ text: "Diagnosis", options: { bold: true, fill: { color: C.navy }, color: C.white } },
{ text: "Key History Clue", options: { bold: true, fill: { color: C.navy }, color: C.white } },
{ text: "Action", options: { bold: true, fill: { color: C.navy }, color: C.white } },
],
[{ text: "Cauda Equina Syndrome", options: { bold: true, color: C.orange } }, "Bilateral legs + bladder/bowel dysfunction + saddle anaesthesia", { text: "EMERGENCY MRI → neurosurgery same day", options: { bold: true, color: C.orange } }],
["Cord compression / myelopathy", "Bilateral progressive weakness, spasticity, hand clumsiness", "Urgent MRI whole spine"],
["Spinal metastases", "Night pain + cancer history + age > 50 + weight loss", "MRI ± bone scan, oncology referral"],
["Epidural abscess", "Fever + severe back pain + IVDU / recent procedure / immunocompromised", "MRI + IV antibiotics, urgent drainage"],
["AAA rupture", "Elderly male + severe back/flank pain + hypotension + pulsatile mass", "Emergency vascular surgery"],
["Septic arthritis (knee/hip)", "Hot joint + fever + inability to weight bear + raised WBC/CRP", "Joint aspiration + IV antibiotics"],
["Pathological fracture", "Minimal trauma + osteoporosis / malignancy history", "X-ray/CT + bone density + oncology"],
["Hip fracture → knee pain", "Elderly fall + cannot weight bear + hip exam positive", "X-ray hip ± CT"],
["ACL rupture → haemarthrosis", "'Pop' + immediate large effusion + giving way", "MRI knee + orthopaedic referral"],
];
s.addTable(mntm, {
x: 4.5, y: 1.42, w: 8.5, h: 5.15,
fontFace: "Calibri", fontSize: 9.5,
border: { pt: 0.5, color: C.lightGrey },
rowH: 0.46,
align: "left",
valign: "middle",
autoPage: false,
});
// Investigation summary footer
s.addShape(pres.ShapeType.roundRect, {
x: 0.3, y: 4.15, w: 4.0, h: 2.7,
fill: { color: C.white }, line: { color: C.teal, width: 1.5 }, rectRadius: 0.1,
});
s.addText("📋 Investigation Principles", {
x: 0.4, y: 4.18, w: 3.8, h: 0.38,
fontSize: 11, bold: true, color: C.teal, fontFace: "Calibri", margin: 0,
});
const invPrinciples = [
"No red flags + < 6 weeks: conservative Rx, no imaging needed",
"X-ray: fracture, alignment, deformity",
"MRI: soft tissue, neural, disc (false positive very common!)",
"Blood: ESR, CRP, WBC, CMP, ALP, PSA, SPEP",
"ESR ≥50 LR+ 19.2 for cancer-related LBP",
"Correlate imaging with clinical findings always",
];
const ipB = invPrinciples.map((t, i) => ({ text: t, options: { bullet: { type: "bullet" }, breakLine: i < invPrinciples.length - 1 } }));
s.addText(ipB, { x: 0.4, y: 4.58, w: 3.7, h: 2.2, fontSize: 9, color: C.darkText, fontFace: "Calibri", valign: "top" });
// Source footer
s.addShape(pres.ShapeType.rect, { x: 0, y: 7.15, w: 13.3, h: 0.35, fill: { color: C.navy } });
s.addText("Sources: Harrison's 22E · Goldman-Cecil Medicine · Tintinalli's EM · Campbell's Operative Orthopaedics 15E · Miller's Review of Orthopaedics 9E · S Das Clinical Surgery 13E · Symptom to Diagnosis 4E", {
x: 0.3, y: 7.17, w: 12.7, h: 0.3,
fontSize: 8, color: C.lightGrey, fontFace: "Calibri", align: "center", margin: 0,
});
}
// ════════════════════════════════════════════════════════════════════
// WRITE FILE
// ════════════════════════════════════════════════════════════════════
pres.writeFile({ fileName: "/home/daytona/workspace/ortho-ddx-pptx/Orthopaedic_DDx_Algorithms.pptx" })
.then(() => console.log("DONE: Orthopaedic_DDx_Algorithms.pptx written successfully"))
.catch(err => { console.error("ERROR:", err); process.exit(1); });