~/osteomyelitis-poster/build_poster.js
const pptxgen = require("pptxgenjs");
const fs = require("fs");
// Load images
const images = JSON.parse(fs.readFileSync("/home/daytona/workspace/osteomyelitis-poster/images.json"));
const img = {};
const urls = [
"4732ddb81e78e31e89dc1e21c97601e082b1405bba5480593863baf467873c6f", // [0] hematogenous spread diagram
"e83fd0f264806a68553cae82263600e1785e2686eec72e1819ef879a16764cd5", // [1] bone abscess anatomy
"dd8e3ef10b89a9003d848e81343bbac22b8a7388e2c20ac8cce085c867dbe5d7", // [2] joint spread diagram
"407ff4d4c5193e5071c7911cfc4a538d051a419d3480b098ab1ff538dcf524d9", // [3] gross pathology sequestrum
"1cf3b081e38306134a895e0958682b57eacdb683bcffb4d568ae1f9474577bc1", // [4] Brodie abscess xray
"bc19268ff7b4d4d0c1f6b6f5485c82fcdfbd9c598f8b1b58a9a3c969880ec9e5", // [5] sequestrum tibia xray
"a0c2103869355b0b49eb5135ff9c8bed3505bd64778d92df683950a58668d702", // [6] types of osteomyelitis diagram
"205bc6043834c1f15a18357d1d39d65ccfc708774011904d340d0e03940137d8", // [7] diagnostic flowchart
];
images.forEach((item, i) => { img[i] = item.base64; });
// ─── Color Palette ───────────────────────────────────────────────────
const C = {
navy: "0D2B55", // dominant dark navy
teal: "0B6E8C", // mid-tone teal
ltblue: "D6EAF2", // light panel background
orange: "E06B2D", // accent/highlight
gold: "F0A500", // table header
white: "FFFFFF",
offwht: "F4F7FB",
dark: "1A1A2E",
gray: "555555",
ltgray: "E8EEF4",
red: "C0392B",
green: "1A7A4A",
yellow: "FFF9C4",
teallt: "B2D8E4",
};
let pres = new pptxgen();
pres.layout = "LAYOUT_WIDE"; // 13.3" x 7.5"
pres.title = "Osteomyelitis - Exam Revision Poster";
// ────────────────────────────────────────────────────────────────────────
// Helper: Add slide header bar
// ────────────────────────────────────────────────────────────────────────
function addHeader(slide, title, subtitle) {
// Dark navy top bar
slide.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 13.3, h: 0.7, fill: { color: C.navy }, line: { color: C.navy } });
// Orange accent stripe
slide.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0.7, w: 13.3, h: 0.07, fill: { color: C.orange }, line: { color: C.orange } });
slide.addText(title, { x: 0.2, y: 0.05, w: 9, h: 0.6, fontSize: 22, bold: true, color: C.white, fontFace: "Calibri", margin: 0 });
if (subtitle) {
slide.addText(subtitle, { x: 9.3, y: 0.1, w: 3.8, h: 0.5, fontSize: 10, color: C.teallt, fontFace: "Calibri", align: "right", italic: true, margin: 0 });
}
// Slide background
slide.background = { color: C.offwht };
}
// ────────────────────────────────────────────────────────────────────────
// Helper: Section label box
// ────────────────────────────────────────────────────────────────────────
function sectionLabel(slide, text, x, y, w, h, bg, fg) {
bg = bg || C.teal;
fg = fg || C.white;
slide.addShape(pres.shapes.RECTANGLE, { x, y, w, h, fill: { color: bg }, line: { color: bg } });
slide.addText(text, { x, y, w, h, fontSize: 9, bold: true, color: fg, fontFace: "Calibri", align: "center", valign: "middle", margin: 0 });
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 1 - TITLE / OVERVIEW
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
slide.background = { color: C.navy };
// Large title
slide.addText("OSTEOMYELITIS", {
x: 0.5, y: 1.1, w: 12.3, h: 1.4,
fontSize: 56, bold: true, color: C.white, fontFace: "Calibri",
align: "center", charSpacing: 8
});
// Subtitle
slide.addText("Comprehensive Exam Revision Notes", {
x: 0.5, y: 2.55, w: 12.3, h: 0.55,
fontSize: 22, color: C.gold, fontFace: "Calibri", align: "center", italic: true
});
// Orange divider
slide.addShape(pres.shapes.RECTANGLE, { x: 3.5, y: 3.2, w: 6.3, h: 0.07, fill: { color: C.orange }, line: { color: C.orange } });
// Definition box
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 1.5, y: 3.4, w: 10.3, h: 1.35, fill: { color: "152040" }, line: { color: C.teal, pt: 2 }, rectRadius: 0.1 });
slide.addText([
{ text: "DEFINITION: ", options: { bold: true, color: C.gold } },
{ text: "Osteomyelitis is infection and inflammation of bone and bone marrow. It may complicate systemic infection but frequently manifests as a solitary primary focus. Pyogenic bacteria and mycobacteria are the most common causes.", options: { color: C.white } }
], { x: 1.7, y: 3.5, w: 9.9, h: 1.1, fontSize: 13, fontFace: "Calibri", valign: "middle" });
// Bottom row - quick facts
const facts = [
{ label: "Most Common\nOrganism", val: "S. aureus\n(80–90%)" },
{ label: "Preferred\nSite", val: "Metaphysis\n(long bones)" },
{ label: "Key Pathology", val: "Sequestrum &\nInvolucrum" },
{ label: "Best\nImaging", val: "MRI\n(gold standard)" },
{ label: "X-ray Lag", val: "10–21 days\nbehind disease" },
];
facts.forEach((f, i) => {
const x = 0.5 + i * 2.47;
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x, y: 5.0, w: 2.27, h: 1.4, fill: { color: C.teal }, line: { color: C.orange, pt: 1.5 }, rectRadius: 0.1 });
slide.addText(f.label, { x, y: 5.05, w: 2.27, h: 0.45, fontSize: 9, bold: true, color: C.teallt, fontFace: "Calibri", align: "center" });
slide.addText(f.val, { x, y: 5.5, w: 2.27, h: 0.8, fontSize: 13, bold: true, color: C.white, fontFace: "Calibri", align: "center" });
});
// Source
slide.addText("Sources: Bailey & Love 28e | Robbins Pathology | Campbell's Orthopaedics 15e | Rosen's EM | Rockwood & Green 10e", {
x: 0, y: 7.3, w: 13.3, h: 0.2, fontSize: 7, color: "6699BB", align: "center", italic: true
});
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 2 - ROUTES + PATHOGENESIS + HAEMATOGENOUS SPREAD IMAGE
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
addHeader(slide, "ROUTES OF INFECTION & PATHOGENESIS", "Bailey & Love 28e | Robbins Pathology");
// LEFT COLUMN - Routes box
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 4.0, h: 3.1, fill: { color: C.ltblue }, line: { color: C.teal, pt: 1.5 } });
sectionLabel(slide, "ROUTES OF INFECTION", 0.15, 0.85, 4.0, 0.32, C.teal, C.white);
const routes = [
{ title: "1. HAEMATOGENOUS (Most common in children)", body: "Bacteraemia seeds metaphyseal sinusoidal vessels\nSlow sinusoidal flow + microtrauma = seeding site\nCommon sites: distal femur, proximal tibia, proximal humerus" },
{ title: "2. CONTIGUOUS SPREAD", body: "Infection spreads from adjacent soft tissues / joints\nE.g. diabetic foot, dental abscess → jaw bone" },
{ title: "3. DIRECT INOCULATION", body: "Open fractures, surgery, puncture wounds\nBite wounds, burns, prosthetic procedures\nOften POLYMICROBIAL" },
];
routes.forEach((r, i) => {
const y = 1.25 + i * 0.88;
slide.addShape(pres.shapes.RECTANGLE, { x: 0.2, y, w: 3.9, h: 0.22, fill: { color: C.teal }, line: { color: C.teal } });
slide.addText(r.title, { x: 0.25, y, w: 3.8, h: 0.22, fontSize: 8, bold: true, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0 });
slide.addText(r.body, { x: 0.25, y: y + 0.23, w: 3.8, h: 0.6, fontSize: 8, color: C.dark, fontFace: "Calibri" });
});
// MIDDLE - Haematogenous diagram image
slide.addShape(pres.shapes.RECTANGLE, { x: 4.25, y: 0.85, w: 4.5, h: 3.1, fill: { color: C.white }, line: { color: C.teal, pt: 1 } });
slide.addImage({ data: img[0], x: 4.3, y: 0.9, w: 4.4, h: 2.75, altText: "Haematogenous spread diagram" });
slide.addText("Fig: Bacterial seeding of metaphyseal sinusoidal vessels via bacteraemia + microtrauma", {
x: 4.25, y: 3.65, w: 4.5, h: 0.32, fontSize: 7.5, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
// RIGHT - Bone anatomy image
slide.addShape(pres.shapes.RECTANGLE, { x: 8.85, y: 0.85, w: 4.3, h: 3.1, fill: { color: C.white }, line: { color: C.teal, pt: 1 } });
slide.addImage({ data: img[1], x: 8.9, y: 0.9, w: 4.2, h: 2.75 });
slide.addText("Fig: Bone abscess formation — pus under periosteum, cortex and medullary cavity", {
x: 8.85, y: 3.65, w: 4.3, h: 0.32, fontSize: 7.5, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
// BOTTOM - Site by age table
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 4.05, w: 13.0, h: 0.3, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("SITE OF INVOLVEMENT BY AGE", { x: 0.15, y: 4.05, w: 13.0, h: 0.3, fontSize: 10, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const ageRows = [
["Age Group", "Site Involved", "Reason", "Common Organisms"],
["Neonates\n(<1 month)", "Metaphysis + EPIPHYSIS + Joint\n(all three simultaneously)", "Metaphyseal vessels penetrate growth plate\n→ high incidence of joint involvement", "Group B Strep, E. coli"],
["Children\n(1–16 yrs)", "METAPHYSIS of long bones\n(distal femur, proximal tibia)", "Slow sinusoidal flow\n+ microtrauma during bacteraemia", "S. aureus (80–90%), MRSA in AHO\nStrep pyogenes, Kingella kingae"],
["Adults", "Epiphysis + subchondral region\nVertebrae (haematogenous)", "Growth plate closure creates anastomoses\nbetween metaphyseal & epiphyseal vessels", "S. aureus, polymicrobial\n(post-surgery/fracture)"],
];
const colW = [2.0, 3.5, 4.3, 3.05];
const startX = 0.15;
const startY = 4.38;
const rowH = [0.3, 0.55, 0.55, 0.55];
let curY = startY;
ageRows.forEach((row, ri) => {
let curX = startX;
row.forEach((cell, ci) => {
const isHeader = ri === 0;
const bg = isHeader ? C.teal : (ri % 2 === 0 ? C.ltblue : C.white);
slide.addShape(pres.shapes.RECTANGLE, { x: curX, y: curY, w: colW[ci], h: rowH[ri], fill: { color: bg }, line: { color: C.teallt, pt: 0.5 } });
slide.addText(cell, { x: curX + 0.05, y: curY, w: colW[ci] - 0.1, h: rowH[ri], fontSize: isHeader ? 8.5 : 8, bold: isHeader, color: isHeader ? C.white : C.dark, fontFace: "Calibri", valign: "middle" });
curX += colW[ci];
});
curY += rowH[ri];
});
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 3 - PATHOLOGY PROGRESSION + GROSS SPECIMEN + TERMS
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
addHeader(slide, "PATHOLOGY — PROGRESSION, KEY TERMS & GROSS SPECIMEN", "Robbins Pathology | Bailey & Love 28e");
// LEFT: Flowchart of pathology
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 5.2, h: 6.5, fill: { color: C.ltblue }, line: { color: C.teal, pt: 1.5 } });
sectionLabel(slide, "PATHOGENESIS FLOWCHART", 0.15, 0.85, 5.2, 0.3, C.navy, C.white);
const flowSteps = [
{ text: "Bacteraemia + Metaphyseal Microtrauma", bg: C.navy, fg: C.white },
{ text: "↓", bg: C.offwht, fg: C.orange },
{ text: "Bacterial seeding of metaphysis\n(sinusoidal slow-flow vessels)", bg: C.teal, fg: C.white },
{ text: "↓", bg: C.offwht, fg: C.orange },
{ text: "Acute inflammation → NEUTROPHILS\nNecrosis of bone & marrow (within 48 hrs)", bg: "1A6B8A", fg: C.white },
{ text: "↓", bg: C.offwht, fg: C.orange },
{ text: "Spread via Haversian canals → PERIOSTEUM\nSubperiosteal abscess formation", bg: "246E8C", fg: C.white },
{ text: "↓", bg: C.offwht, fg: C.orange },
{ text: "Periosteal elevation → ↓ blood supply\n→ MORE NECROSIS", bg: C.orange, fg: C.white },
{ text: "↓ (if untreated)", bg: C.offwht, fg: C.gray },
{ text: "SEQUESTRUM = Dead necrotic cortical bone\nINVOLUCRUM = New periosteal bone shell", bg: C.red, fg: C.white },
{ text: "↓", bg: C.offwht, fg: C.orange },
{ text: "Cloacae → Sinus tracts → Skin surface\n\"Bone-within-bone\" on X-ray", bg: "6B2737", fg: C.white },
];
const stepStartY = 1.22;
const stepH = [0.28, 0.2, 0.33, 0.2, 0.35, 0.2, 0.35, 0.2, 0.33, 0.2, 0.37, 0.2, 0.33];
let sy = stepStartY;
flowSteps.forEach((step, i) => {
if (step.text.startsWith("↓")) {
slide.addText(step.text, { x: 0.2, y: sy, w: 5.05, h: stepH[i], fontSize: step.text === "↓" ? 16 : 9, color: step.fg, fontFace: "Calibri", align: "center", bold: true });
} else {
slide.addShape(pres.shapes.RECTANGLE, { x: 0.25, y: sy, w: 4.95, h: stepH[i], fill: { color: step.bg }, line: { color: step.bg } });
slide.addText(step.text, { x: 0.3, y: sy, w: 4.85, h: stepH[i], fontSize: 9, bold: true, color: step.fg, fontFace: "Calibri", align: "center", valign: "middle", margin: 0 });
}
sy += stepH[i];
});
// MIDDLE - Joint spread image + key terms table
// Image
slide.addShape(pres.shapes.RECTANGLE, { x: 5.5, y: 0.85, w: 3.9, h: 2.8, fill: { color: C.white }, line: { color: C.teal, pt: 1 } });
slide.addImage({ data: img[2], x: 5.55, y: 0.9, w: 3.8, h: 2.6 });
slide.addText("Fig: Spread of bone abscess into joint cavity\n(esp. in neonates — intracapsular metaphysis)", {
x: 5.5, y: 3.65, w: 3.9, h: 0.35, fontSize: 7.5, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
// Histological stages table
slide.addShape(pres.shapes.RECTANGLE, { x: 5.5, y: 4.1, w: 3.9, h: 0.28, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("HISTOLOGICAL STAGES", { x: 5.5, y: 4.1, w: 3.9, h: 0.28, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const histRows = [
["Stage", "Time", "Histology"],
["ACUTE", "0–48 hrs", "Neutrophilic infiltrate, bone + marrow necrosis"],
["SUBACUTE", "Days–weeks", "Chronic inflammatory cells, bone resorption, fibrous tissue ingrowth"],
["CHRONIC", "Weeks+", "Marrow fibrosis, sequestrum, lymphocytes + plasma cells, involucrum"],
];
const hColW = [1.0, 0.9, 1.95];
let hCurY = 4.38;
histRows.forEach((row, ri) => {
let hCurX = 5.5;
row.forEach((cell, ci) => {
const isH = ri === 0;
const bg = isH ? C.teal : (ri % 2 === 0 ? C.ltblue : C.white);
slide.addShape(pres.shapes.RECTANGLE, { x: hCurX, y: hCurY, w: hColW[ci], h: 0.38, fill: { color: bg }, line: { color: C.teallt, pt: 0.5 } });
slide.addText(cell, { x: hCurX + 0.04, y: hCurY, w: hColW[ci] - 0.08, h: 0.38, fontSize: isH ? 8 : 7.5, bold: isH, color: isH ? C.white : C.dark, fontFace: "Calibri", valign: "middle" });
hCurX += hColW[ci];
});
hCurY += 0.38;
});
// RIGHT - Gross Pathology + key terms
slide.addShape(pres.shapes.RECTANGLE, { x: 9.55, y: 0.85, w: 3.6, h: 3.1, fill: { color: C.white }, line: { color: C.teal, pt: 1 } });
slide.addImage({ data: img[3], x: 9.6, y: 0.9, w: 3.5, h: 2.7 });
slide.addText("Fig: Resected femur — sequestrum inside involucrum (Robbins Pathology Fig 26.16)", {
x: 9.55, y: 3.65, w: 3.6, h: 0.35, fontSize: 7.5, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
// KEY TERMS
slide.addShape(pres.shapes.RECTANGLE, { x: 9.55, y: 4.1, w: 3.6, h: 0.28, fill: { color: C.orange }, line: { color: C.orange } });
slide.addText("KEY PATHOLOGICAL TERMS", { x: 9.55, y: 4.1, w: 3.6, h: 0.28, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const terms = [
{ term: "Sequestrum", def: "Dead necrotic cortical bone — hallmark of chronic OM; acts as nidus for infection" },
{ term: "Involucrum", def: "Shell of new reactive periosteal bone around sequestrum; 'bone-within-bone' on X-ray" },
{ term: "Cloaca", def: "Openings in involucrum through which pus drains" },
{ term: "Brodie Abscess", def: "Chronic walled-off abscess; well-defined lytic lesion + sclerotic rim" },
{ term: "Sinus Tract", def: "Channel from medullary cavity to skin; longstanding → risk of SCC (Marjolin's)" },
];
let termY = 4.42;
terms.forEach((t, i) => {
const bg = i % 2 === 0 ? C.ltblue : C.white;
slide.addShape(pres.shapes.RECTANGLE, { x: 9.55, y: termY, w: 3.6, h: 0.44, fill: { color: bg }, line: { color: C.teallt, pt: 0.3 } });
slide.addText([
{ text: t.term + ": ", options: { bold: true, color: C.teal, fontSize: 8 } },
{ text: t.def, options: { color: C.dark, fontSize: 7.5 } }
], { x: 9.6, y: termY + 0.03, w: 3.5, h: 0.38, fontFace: "Calibri", valign: "top" });
termY += 0.44;
});
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 4 - MICROBIOLOGY + CLASSIFICATION
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
addHeader(slide, "MICROBIOLOGY & CLASSIFICATION (CIERNY-MADER)", "Rockwood & Green 10e | Campbell's Orthopaedics 15e");
// LEFT - Microbiology table
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 5.6, h: 0.28, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("MICROBIOLOGY — ORGANISMS BY SETTING", { x: 0.15, y: 0.85, w: 5.6, h: 0.28, fontSize: 9.5, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const microRows = [
["Patient Group", "Most Likely Organisms", "Notes"],
["Neonates", "Group B Strep, E. coli", "Metaphysis + epiphysis + joint"],
["Children (general)", "S. aureus (MRSA in AHO), Strep pyogenes, Kingella kingae", "Male:female = 2:1 to 3:1"],
["Adults", "S. aureus (80–90% culture-positive)", "Hematogenous or post-traumatic"],
["Sickle Cell Disease", "Salmonella + gram-negatives", "Osteonecrosis = nidus; impaired spleen"],
["Post-surgery / Open Fx", "Polymicrobial, gram-negatives", "Gustilo grading guides Abx"],
["IV Drug Users", "S. aureus, Pseudomonas", "Unusual sites (spine, clavicle)"],
["Immunocompromised", "Fungi (Candida, Aspergillus)", "Consider if not improving"],
["TB Osteomyelitis", "Mycobacterium tuberculosis", "1–3% of TB cases; more destructive"],
];
const mColW = [2.1, 2.4, 1.0];
let mCurY = 1.16;
microRows.forEach((row, ri) => {
let mCurX = 0.15;
row.forEach((cell, ci) => {
const isH = ri === 0;
const bg = isH ? C.teal : (ri % 2 === 0 ? C.ltblue : C.white);
slide.addShape(pres.shapes.RECTANGLE, { x: mCurX, y: mCurY, w: mColW[ci], h: 0.42, fill: { color: bg }, line: { color: C.teallt, pt: 0.4 } });
slide.addText(cell, { x: mCurX + 0.04, y: mCurY, w: mColW[ci] - 0.08, h: 0.42, fontSize: isH ? 8 : 7.5, bold: isH, color: isH ? C.white : C.dark, fontFace: "Calibri", valign: "middle" });
mCurX += mColW[ci];
});
mCurY += 0.42;
});
// Staph note
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 0.15, y: 4.98, w: 5.6, h: 0.45, fill: { color: "FFF3CD" }, line: { color: C.gold, pt: 1 }, rectRadius: 0.05 });
slide.addText("★ Why S. aureus? Staphylococcal cell wall proteins bind bone matrix components (collagen) → facilitating bacterial adherence to bone. Cultures only identify organism in ~50% cases; PCR improving this.", {
x: 0.2, y: 4.99, w: 5.5, h: 0.43, fontSize: 7.5, color: "5D4037", fontFace: "Calibri", valign: "middle"
});
// MIDDLE/RIGHT - Cierny-Mader Classification
slide.addShape(pres.shapes.RECTANGLE, { x: 5.9, y: 0.85, w: 7.25, h: 0.28, fill: { color: C.orange }, line: { color: C.orange } });
slide.addText("CIERNY-MADER CLASSIFICATION — CHRONIC OSTEOMYELITIS (Most Widely Used System)", {
x: 5.9, y: 0.85, w: 7.25, h: 0.28, fontSize: 9.5, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0
});
// Anatomic types
slide.addShape(pres.shapes.RECTANGLE, { x: 5.9, y: 1.16, w: 3.55, h: 0.25, fill: { color: C.teal }, line: { color: C.teal } });
slide.addText("ANATOMIC TYPES (4)", { x: 5.9, y: 1.16, w: 3.55, h: 0.25, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const anatTypes = [
["Type I", "Medullary", "Endosteal / intramedullary only"],
["Type II", "Superficial", "Cortical surface infected — coverage defect"],
["Type III", "Localized", "Full-thickness cortical sequestrum; stable bone"],
["Type IV", "Diffuse", "Permeative infection; MECHANICALLY UNSTABLE bone"],
];
const aColW = [0.6, 0.9, 2.0];
let aCurY = 1.44;
anatTypes.forEach((row, ri) => {
let aCurX = 5.9;
row.forEach((cell, ci) => {
const bg = ri % 2 === 0 ? C.ltblue : C.white;
slide.addShape(pres.shapes.RECTANGLE, { x: aCurX, y: aCurY, w: aColW[ci], h: 0.42, fill: { color: bg }, line: { color: C.teallt, pt: 0.4 } });
const isBold = ci === 0;
slide.addText(cell, { x: aCurX + 0.04, y: aCurY, w: aColW[ci] - 0.08, h: 0.42, fontSize: 8, bold: isBold, color: isBold ? C.teal : C.dark, fontFace: "Calibri", valign: "middle" });
aCurX += aColW[ci];
});
aCurY += 0.42;
});
// Physiologic classes
slide.addShape(pres.shapes.RECTANGLE, { x: 5.9, y: 3.18, w: 3.55, h: 0.25, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("PHYSIOLOGIC HOST CLASSES (3)", { x: 5.9, y: 3.18, w: 3.55, h: 0.25, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const hostClasses = [
["A Host", "Normal", "Immunocompetent, good local vascularity"],
["B Host", "Compromised", "Bᴸ = local factors; Bˢ = systemic factors"],
["C Host", "Prohibitive", "Treatment worse than disease; poor prognosis; not surgical candidate"],
];
const hcColW = [0.7, 0.9, 1.9];
let hcCurY = 3.46;
hostClasses.forEach((row, ri) => {
let hcCurX = 5.9;
row.forEach((cell, ci) => {
const bgs = [C.ltblue, C.white, C.ltblue];
slide.addShape(pres.shapes.RECTANGLE, { x: hcCurX, y: hcCurY, w: hcColW[ci], h: 0.47, fill: { color: bgs[ri] }, line: { color: C.teallt, pt: 0.4 } });
slide.addText(cell, { x: hcCurX + 0.04, y: hcCurY, w: hcColW[ci] - 0.08, h: 0.47, fontSize: 8, bold: ci === 0, color: ci === 0 ? C.orange : C.dark, fontFace: "Calibri", valign: "middle" });
hcCurX += hcColW[ci];
});
hcCurY += 0.47;
});
// Staging note
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 5.9, y: 4.95, w: 3.55, h: 0.48, fill: { color: "FFF3CD" }, line: { color: C.gold, pt: 1 }, rectRadius: 0.05 });
slide.addText("4 Anatomic Types × 3 Host Classes = 12 Clinical Stages\nE.g. Type II + B Host → Stage IIB Chronic Osteomyelitis", {
x: 5.95, y: 4.96, w: 3.45, h: 0.46, fontSize: 8, color: "5D4037", fontFace: "Calibri", bold: true
});
// RIGHT side - types of OM body diagram
slide.addShape(pres.shapes.RECTANGLE, { x: 9.55, y: 1.16, w: 3.6, h: 3.45, fill: { color: C.white }, line: { color: C.teal, pt: 1 } });
slide.addImage({ data: img[6], x: 9.6, y: 1.2, w: 3.5, h: 3.1 });
slide.addText("Fig: Types of Osteomyelitis — Vertebral, Metaphyseal, Periprosthetic, Fracture-related, Diabetic foot (Rockwood & Green 10e)", {
x: 9.55, y: 4.62, w: 3.6, h: 0.38, fontSize: 7, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
// By duration
slide.addShape(pres.shapes.RECTANGLE, { x: 9.55, y: 5.02, w: 3.6, h: 0.25, fill: { color: C.teal }, line: { color: C.teal } });
slide.addText("CLASSIFICATION BY DURATION", { x: 9.55, y: 5.02, w: 3.6, h: 0.25, fontSize: 8.5, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const durRows = [
["Type", "Duration", "Key Feature"],
["Acute", "< 2 wks", "Inflammatory, no bone destruction"],
["Subacute", "2–6 wks", "Brodie abscess may form"],
["Chronic", "> 6 wks", "Sequestrum + involucrum evident"],
];
const dColW = [0.85, 0.9, 1.8];
let dCurY = 5.3;
durRows.forEach((row, ri) => {
let dCurX = 9.55;
row.forEach((cell, ci) => {
const isH = ri === 0;
const bg = isH ? C.navy : (ri % 2 === 0 ? C.ltblue : C.white);
slide.addShape(pres.shapes.RECTANGLE, { x: dCurX, y: dCurY, w: dColW[ci], h: 0.38, fill: { color: bg }, line: { color: C.teallt, pt: 0.4 } });
slide.addText(cell, { x: dCurX + 0.04, y: dCurY, w: dColW[ci] - 0.08, h: 0.38, fontSize: isH ? 7.5 : 7.5, bold: isH, color: isH ? C.white : C.dark, fontFace: "Calibri", valign: "middle" });
dCurX += dColW[ci];
});
dCurY += 0.38;
});
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 5 - CLINICAL FEATURES + INVESTIGATIONS + RADIOLOGY
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
addHeader(slide, "CLINICAL FEATURES, INVESTIGATIONS & RADIOLOGY", "Rosen's Emergency Medicine | Campbell's Orthopaedics 15e | Grainger & Allison");
// LEFT: Clinical features
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 4.3, h: 0.28, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("CLINICAL FEATURES", { x: 0.15, y: 0.85, w: 4.3, h: 0.28, fontSize: 10, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
// Acute features - two sub-boxes
sectionLabel(slide, "ACUTE — SYSTEMIC", 0.15, 1.15, 2.1, 0.25, C.red, C.white);
const systemicFeatures = ["High fever + rigors", "Malaise, fatigue", "Anorexia, headache", "May appear toxic", "Tachycardia"];
systemicFeatures.forEach((f, i) => {
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 1.42 + i * 0.3, w: 2.1, h: 0.28, fill: { color: i % 2 === 0 ? "FDECEA" : C.white }, line: { color: "FFCDD2", pt: 0.3 } });
slide.addText("• " + f, { x: 0.2, y: 1.42 + i * 0.3, w: 2.0, h: 0.28, fontSize: 8, color: C.dark, fontFace: "Calibri", valign: "middle" });
});
sectionLabel(slide, "ACUTE — LOCAL", 2.28, 1.15, 2.15, 0.25, "1A6B4A", C.white);
const localFeatures = ["Point tenderness ★", "Swelling + warmth", "Erythema", "Sympathetic effusion", "Limp / can't weight bear"];
localFeatures.forEach((f, i) => {
slide.addShape(pres.shapes.RECTANGLE, { x: 2.28, y: 1.42 + i * 0.3, w: 2.15, h: 0.28, fill: { color: i % 2 === 0 ? "E8F5E9" : C.white }, line: { color: "C8E6C9", pt: 0.3 } });
slide.addText("• " + f, { x: 2.33, y: 1.42 + i * 0.3, w: 2.05, h: 0.28, fontSize: 8, color: C.dark, fontFace: "Calibri", valign: "middle" });
});
// Chronic features
sectionLabel(slide, "CHRONIC OSTEOMYELITIS", 0.15, 2.97, 4.3, 0.25, C.teal, C.white);
const chronicF = ["Systemic symptoms less prominent", "Palpable sequestrum / involucrum", "SINUS TRACTS discharging pus", "Recurrent flares after years of dormancy", "Draining wound (long-standing)"];
chronicF.forEach((f, i) => {
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 3.25 + i * 0.3, w: 4.3, h: 0.28, fill: { color: i % 2 === 0 ? C.ltblue : C.white }, line: { color: C.teallt, pt: 0.3 } });
slide.addText("• " + f, { x: 0.2, y: 3.25 + i * 0.3, w: 4.2, h: 0.28, fontSize: 8, color: C.dark, fontFace: "Calibri", valign: "middle" });
});
// Complications box
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 4.78, w: 4.3, h: 0.25, fill: { color: C.red }, line: { color: C.red } });
slide.addText("COMPLICATIONS", { x: 0.15, y: 4.78, w: 4.3, h: 0.25, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const comps = [
"Acute: Bacteraemia/Sepsis, Septic arthritis (esp. neonates), Growth arrest, Pathologic fracture",
"Chronic: Secondary amyloidosis, Endocarditis, Pathologic fracture",
"★ Marjolin's: SCC in longstanding sinus tract — increased pain + foul smell → BIOPSY",
];
comps.forEach((c, i) => {
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 5.05 + i * 0.37, w: 4.3, h: 0.35, fill: { color: i === 2 ? "FFF3CD" : (i % 2 === 0 ? "FDECEA" : C.white) }, line: { color: "FFCDD2", pt: 0.3 } });
slide.addText(c, { x: 0.2, y: 5.05 + i * 0.37, w: 4.2, h: 0.35, fontSize: 7.5, color: i === 2 ? "5D4037" : C.dark, fontFace: "Calibri", valign: "middle" });
});
// MIDDLE - Investigations table
slide.addShape(pres.shapes.RECTANGLE, { x: 4.6, y: 0.85, w: 5.0, h: 0.28, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("INVESTIGATIONS", { x: 4.6, y: 0.85, w: 5.0, h: 0.28, fontSize: 10, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const invRows = [
["Test", "Finding", "Comment"],
["WBC", "↑ Leukocytosis", "Variable; may be normal"],
["ESR", "↑↑ (often >50 mm/hr)", "Sensitive; slow to normalize; use to monitor"],
["CRP", "↑↑ elevated", "Faster rise & fall than ESR; better for monitoring treatment"],
["Blood Culture", "+ve ~40% in AHO", "Always send BEFORE antibiotics"],
["Bone Biopsy", "Gold standard", "Histology + culture — essential for pathogen ID"],
["X-ray", "Soft tissue swelling (early)\nCortical destruction + periosteal reaction (late)", "Lag of 10–21 days! Always first investigation"],
["Ultrasound", "Subperiosteal fluid/abscess", "Best in infants; non-invasive; guides aspiration"],
["CT", "Cortical destruction; detects sequestra", "Guides needle aspiration; great for sequestrum"],
["MRI", "High T2 signal; ring enhancement of abscess;\nPenumbra sign (Brodie)", "Highest sensitivity + specificity; GOLD STANDARD"],
["Bone Scan\n(⁹⁹ᵐTc-MDP)", "3-phase uptake", "If MRI unavailable; false -ve in neonates"],
];
const iColW = [1.15, 1.9, 1.9];
let iCurY = 1.16;
invRows.forEach((row, ri) => {
let iCurX = 4.6;
const rH = (ri >= 6) ? 0.46 : 0.36;
row.forEach((cell, ci) => {
const isH = ri === 0;
const bg = isH ? C.teal : (ri % 2 === 0 ? C.ltblue : C.white);
slide.addShape(pres.shapes.RECTANGLE, { x: iCurX, y: iCurY, w: iColW[ci], h: rH, fill: { color: bg }, line: { color: C.teallt, pt: 0.4 } });
slide.addText(cell, { x: iCurX + 0.04, y: iCurY, w: iColW[ci] - 0.08, h: rH, fontSize: isH ? 8 : 7.5, bold: isH, color: isH ? C.white : C.dark, fontFace: "Calibri", valign: "middle" });
iCurX += iColW[ci];
});
iCurY += rH;
});
// RIGHT - X-ray images
slide.addShape(pres.shapes.RECTANGLE, { x: 9.75, y: 0.85, w: 3.4, h: 2.9, fill: { color: C.white }, line: { color: C.teal, pt: 1 } });
slide.addImage({ data: img[4], x: 9.8, y: 0.9, w: 3.3, h: 2.55 });
slide.addText("Fig: Brodie abscess — distal tibial epiphysis, 3-year-old\n(well-defined lytic lesion + sclerotic rim)", {
x: 9.75, y: 3.75, w: 3.4, h: 0.38, fontSize: 7.5, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
slide.addShape(pres.shapes.RECTANGLE, { x: 9.75, y: 4.2, w: 3.4, h: 2.65, fill: { color: C.white }, line: { color: C.teal, pt: 1 } });
slide.addImage({ data: img[5], x: 9.8, y: 4.25, w: 3.3, h: 2.3 });
slide.addText("Fig: Sequestrum of chronic osteomyelitis in tibia — dense fragment within lytic area", {
x: 9.75, y: 6.85, w: 3.4, h: 0.35, fontSize: 7.5, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 6 - DIAGNOSIS FLOWCHART + TREATMENT
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
addHeader(slide, "DIAGNOSIS FLOWCHART & TREATMENT", "Rosen's Emergency Medicine | Bailey & Love 28e | Campbell's Orthopaedics 15e");
// LEFT - Diagnostic flowchart image
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 4.5, h: 5.0, fill: { color: C.white }, line: { color: C.teal, pt: 1.5 } });
slide.addText("DIAGNOSTIC ALGORITHM", { x: 0.15, y: 0.85, w: 4.5, h: 0.28, fontSize: 9.5, bold: true, color: C.white, fontFace: "Calibri", align: "center", fill: { color: C.navy } });
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 4.5, h: 0.28, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("DIAGNOSTIC ALGORITHM", { x: 0.15, y: 0.85, w: 4.5, h: 0.28, fontSize: 9.5, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
slide.addImage({ data: img[7], x: 0.25, y: 1.2, w: 4.3, h: 4.45 });
slide.addText("Fig: Imaging algorithm for diagnosis of osteomyelitis in ED — Rosen's Emergency Medicine Fig 125.2", {
x: 0.15, y: 5.88, w: 4.5, h: 0.3, fontSize: 7, italic: true, color: C.gray, fontFace: "Calibri", align: "center"
});
// MIDDLE - Treatment (Medical)
slide.addShape(pres.shapes.RECTANGLE, { x: 4.8, y: 0.85, w: 4.1, h: 0.28, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("ANTIBIOTIC TREATMENT", { x: 4.8, y: 0.85, w: 4.1, h: 0.28, fontSize: 10, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
// Treatment flowchart
const txSteps = [
{ t: "Confirm diagnosis", sub: "Blood culture + Bone biopsy BEFORE antibiotics (if safe)", bg: C.navy },
{ t: "↓" },
{ t: "Empirical IV antibiotics", sub: "Based on age/setting/local MRSA prevalence", bg: C.teal },
{ t: "↓" },
{ t: "Adjust to sensitivities", sub: "When culture results return (48–72 hrs)", bg: "1A6B8A" },
{ t: "↓" },
{ t: "Monitor CRP + clinical response", sub: "Switch to oral when improving (CRP falling)", bg: C.orange },
{ t: "↓" },
{ t: "Total duration: 4–6 weeks minimum", sub: "Longer for chronic; vertebral = 8–12 wks", bg: C.red },
];
let txY = 1.18;
txSteps.forEach((s) => {
if (s.t === "↓") {
slide.addText("↓", { x: 4.8, y: txY, w: 4.1, h: 0.18, fontSize: 14, color: C.orange, fontFace: "Calibri", align: "center", bold: true });
txY += 0.18;
} else {
slide.addShape(pres.shapes.RECTANGLE, { x: 4.8, y: txY, w: 4.1, h: 0.27, fill: { color: s.bg }, line: { color: s.bg } });
slide.addText(s.t, { x: 4.85, y: txY, w: 4.0, h: 0.27, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0 });
txY += 0.27;
slide.addText(s.sub, { x: 4.85, y: txY, w: 4.0, h: 0.26, fontSize: 8, color: C.dark, fontFace: "Calibri" });
txY += 0.28;
}
});
// Antibiotic table
slide.addShape(pres.shapes.RECTANGLE, { x: 4.8, y: 3.92, w: 4.1, h: 0.25, fill: { color: C.teal }, line: { color: C.teal } });
slide.addText("EMPIRICAL ANTIBIOTIC SELECTION", { x: 4.8, y: 3.92, w: 4.1, h: 0.25, fontSize: 8.5, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const abxRows = [
["Patient", "First Choice", "Alternative"],
["Children (general)", "Flucloxacillin IV", "Clindamycin"],
["Children (MRSA)", "Vancomycin IV", "Linezolid"],
["Adults (community)", "Flucloxacillin / Nafcillin", "Vancomycin"],
["Adults (MRSA)", "Vancomycin IV", "Daptomycin"],
["Sickle Cell", "Fluoroquinolone +\nanti-Staph", "Ceftriaxone"],
["Post-surgical", "Pip-Tazobactam\n(broad spectrum)", "Meropenem"],
["TB Osteomyelitis", "HRZE × 2 months\nthen HR × 10 months", "Per sensitivities"],
];
const abxColW = [1.3, 1.5, 1.25];
let abxY = 4.2;
abxRows.forEach((row, ri) => {
let abxX = 4.8;
row.forEach((cell, ci) => {
const isH = ri === 0;
const bg = isH ? C.navy : (ri % 2 === 0 ? C.ltblue : C.white);
const rH = (ri >= 5) ? 0.43 : 0.33;
slide.addShape(pres.shapes.RECTANGLE, { x: abxX, y: abxY, w: abxColW[ci], h: rH, fill: { color: bg }, line: { color: C.teallt, pt: 0.4 } });
slide.addText(cell, { x: abxX + 0.04, y: abxY, w: abxColW[ci] - 0.08, h: rH, fontSize: isH ? 7.5 : 7.5, bold: isH, color: isH ? C.white : C.dark, fontFace: "Calibri", valign: "middle" });
abxX += abxColW[ci];
});
const rH = (ri >= 5) ? 0.43 : 0.33;
abxY += rH;
});
// RIGHT - Surgical Treatment
slide.addShape(pres.shapes.RECTANGLE, { x: 9.05, y: 0.85, w: 4.1, h: 0.28, fill: { color: C.orange }, line: { color: C.orange } });
slide.addText("SURGICAL TREATMENT", { x: 9.05, y: 0.85, w: 4.1, h: 0.28, fontSize: 10, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const surgRows = [
["Indication", "Procedure"],
["Abscess / pus under pressure", "Drainage (needle or surgical)"],
["Subperiosteal abscess", "Surgical decompression"],
["Sequestrum present", "Sequestrectomy (remove dead bone)"],
["Failed medical management", "Debridement + dead space management"],
["Infected hardware", "Hardware removal (usually)"],
["Soft tissue defect after debridement", "Muscle flap / free flap coverage"],
["Bone defect post-debridement", "Bone graft / Masquelet technique"],
["Refractory / limb-threatening", "Amputation (selected cases)"],
];
const sColW = [2.0, 2.05];
let sCurY = 1.16;
surgRows.forEach((row, ri) => {
let sCurX = 9.05;
row.forEach((cell, ci) => {
const isH = ri === 0;
const bg = isH ? C.teal : (ri % 2 === 0 ? C.ltblue : C.white);
slide.addShape(pres.shapes.RECTANGLE, { x: sCurX, y: sCurY, w: sColW[ci], h: 0.4, fill: { color: bg }, line: { color: C.teallt, pt: 0.4 } });
slide.addText(cell, { x: sCurX + 0.04, y: sCurY, w: sColW[ci] - 0.08, h: 0.4, fontSize: isH ? 8.5 : 7.5, bold: isH, color: isH ? C.white : C.dark, fontFace: "Calibri", valign: "middle" });
sCurX += sColW[ci];
});
sCurY += 0.4;
});
// Dead space management
slide.addShape(pres.shapes.RECTANGLE, { x: 9.05, y: 4.82, w: 4.1, h: 0.25, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("DEAD SPACE MANAGEMENT", { x: 9.05, y: 4.82, w: 4.1, h: 0.25, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const dsItems = [
"• Antibiotic-loaded PMMA cement beads (non-biodegradable)",
"• Biodegradable carriers — calcium sulphate, hydroxyapatite",
"• Muscle / soft tissue flap coverage",
"• Bone transport (Ilizarov) for large defects",
];
dsItems.forEach((d, i) => {
slide.addShape(pres.shapes.RECTANGLE, { x: 9.05, y: 5.1 + i * 0.31, w: 4.1, h: 0.29, fill: { color: i % 2 === 0 ? C.ltblue : C.white }, line: { color: C.teallt, pt: 0.3 } });
slide.addText(d, { x: 9.1, y: 5.1 + i * 0.31, w: 4.0, h: 0.29, fontSize: 8, color: C.dark, fontFace: "Calibri", valign: "middle" });
});
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 7 - SPECIAL FORMS + HIGH-YIELD SUMMARY
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
addHeader(slide, "SPECIAL FORMS & HIGH-YIELD EXAM SUMMARY", "All Sources");
// LEFT - Special forms
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 6.3, h: 0.28, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("SPECIAL FORMS OF OSTEOMYELITIS", { x: 0.15, y: 0.85, w: 6.3, h: 0.28, fontSize: 10, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const specials = [
{
title: "BRODIE ABSCESS (Subacute OM)",
color: C.teal,
points: [
"Chronic walled-off intraosseous abscess",
"Localized pain, minimal systemic symptoms",
"X-ray: Well-defined lytic lesion + SCLEROTIC RIM",
"MRI: PENUMBRA SIGN — high-signal ring (granulation tissue) around low-signal abscess",
"Treatment: Surgical drainage + curettage + antibiotics",
]
},
{
title: "VERTEBRAL OSTEOMYELITIS / POTT'S DISEASE (TB Spine)",
color: C.orange,
points: [
"Adults: vertebral OM often coexists with diskitis",
"Children: isolated diskitis more common",
"Back pain ± radiculopathy ± fever; may refuse to walk",
"MRI best: vertebral + disc involvement + intraspinal complications",
"CT-guided aspiration: cultures positive 30–60%",
"TB spine (Pott's): kyphosis + paraplegia (Pott's paraplegia) as complications",
"Treatment: ATT 12+ months; surgery for instability/cord compression",
]
},
{
title: "TUBERCULOUS DACTYLITIS (Spina Ventosa)",
color: "6B3A9F",
points: [
"Rare TB osteomyelitis of small bones",
"Cyst-like cavities + diaphyseal expansion",
"Hands > Feet",
"Treatment: Standard ATT",
]
},
{
title: "DIABETIC FOOT OSTEOMYELITIS",
color: C.red,
points: [
"Neuropathy masks pain → late presentation",
"Secondary to soft tissue ulceration → CONTIGUOUS spread",
"Plain X-ray first; MRI for extent",
"Management: debridement + prolonged Abx ± revascularization",
"Probe-to-bone test: positive = 89% PPV for osteomyelitis",
]
},
{
title: "POSTTRAUMATIC / POST-SURGICAL OM",
color: "4A5568",
points: [
"Open fractures, burns, bites, surgery",
"Gustilo classification guides antibiotic treatment",
"Often polymicrobial; hardware often needs removal",
"Rate: 0.05% open long-bone fractures; 1–2% prosthetic joints",
"Early (<12 wks): likely surgical contamination; Late: haematogenous",
]
},
];
let spY = 1.17;
specials.forEach((sp) => {
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: spY, w: 6.3, h: 0.24, fill: { color: sp.color }, line: { color: sp.color } });
slide.addText(sp.title, { x: 0.2, y: spY, w: 6.2, h: 0.24, fontSize: 8.5, bold: true, color: C.white, fontFace: "Calibri", valign: "middle", margin: 0 });
spY += 0.24;
const blockH = sp.points.length * 0.26;
sp.points.forEach((p, i) => {
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: spY, w: 6.3, h: 0.24, fill: { color: i % 2 === 0 ? C.ltblue : C.white }, line: { color: C.teallt, pt: 0.3 } });
slide.addText("• " + p, { x: 0.25, y: spY, w: 6.1, h: 0.24, fontSize: 7.5, color: C.dark, fontFace: "Calibri", valign: "middle" });
spY += 0.24;
});
spY += 0.05;
});
// RIGHT - High yield summary
slide.addShape(pres.shapes.RECTANGLE, { x: 6.6, y: 0.85, w: 6.55, h: 0.28, fill: { color: C.orange }, line: { color: C.orange } });
slide.addText("HIGH-YIELD EXAM POINTS ★", { x: 6.6, y: 0.85, w: 6.55, h: 0.28, fontSize: 10, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0 });
const highYield = [
{ num: "1", text: "Most common organism overall = S. aureus (80–90% culture-positive cases)" },
{ num: "2", text: "Sickle cell = Salmonella (osteonecrosis nidus + impaired splenic function)" },
{ num: "3", text: "Neonates = Group B Strep + E. coli; metaphysis AND epiphysis AND joint can all be involved simultaneously" },
{ num: "4", text: "Metaphysis = preferred site due to SLOW sinusoidal blood flow + microtrauma" },
{ num: "5", text: "SEQUESTRUM = dead bone; INVOLUCRUM = new reactive periosteal bone shell around sequestrum" },
{ num: "6", text: "X-ray LAG = 10–21 days behind clinical disease. MRI = investigation of choice for early diagnosis" },
{ num: "7", text: "Brodie abscess = subacute walled-off abscess; lytic lesion + sclerotic rim; PENUMBRA SIGN on MRI" },
{ num: "8", text: "Cierny-Mader = gold standard classification; 4 anatomic types × 3 host classes = 12 stages" },
{ num: "9", text: "MARJOLIN'S: Longstanding draining sinus → SCC (squamous cell carcinoma). Signs: ↑ pain, ↑ discharge, foul smell → BIOPSY" },
{ num: "10", text: "Pott's disease = TB osteomyelitis of spine; complications include kyphosis + paraplegia" },
{ num: "11", text: "Treatment principle = 'Drain pus, give antibiotics'. IV first → switch to oral when clinically improving (CRP falling)" },
{ num: "12", text: "PVL-positive MRSA (Panton-Valentine leukocidin) = more aggressive; higher morbidity; affects antibiotic choice" },
{ num: "13", text: "Diabetic foot OM: CONTIGUOUS spread; late presentation due to neuropathy; probe-to-bone test = 89% PPV" },
{ num: "14", text: "AHO in children: Male > Female (2:1 to 3:1 ratio); blood cultures positive only 40% of cases" },
{ num: "15", text: "Chronic OM: 5–25% of acute OM fails to resolve; complications include amyloidosis, endocarditis, SCC, sarcoma" },
];
highYield.forEach((item, i) => {
const y = 1.17 + i * 0.38;
const bg = i % 2 === 0 ? "FFF8E1" : C.white;
slide.addShape(pres.shapes.RECTANGLE, { x: 6.6, y, w: 6.55, h: 0.36, fill: { color: bg }, line: { color: "FFE082", pt: 0.5 } });
slide.addShape(pres.shapes.RECTANGLE, { x: 6.6, y, w: 0.32, h: 0.36, fill: { color: C.orange }, line: { color: C.orange } });
slide.addText(item.num, { x: 6.6, y, w: 0.32, h: 0.36, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", valign: "middle", margin: 0 });
slide.addText(item.text, { x: 6.95, y: y + 0.01, w: 6.15, h: 0.34, fontSize: 7.5, color: C.dark, fontFace: "Calibri", valign: "middle" });
});
// Bottom source
slide.addShape(pres.shapes.RECTANGLE, { x: 0, y: 7.3, w: 13.3, h: 0.22, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("Bailey & Love 28e | Robbins & Kumar Pathologic Basis of Disease | Campbell's Operative Orthopaedics 15e | Rosen's Emergency Medicine | Rockwood & Green's Fractures in Adults 10e | Grainger & Allison's Diagnostic Radiology", {
x: 0, y: 7.3, w: 13.3, h: 0.22, fontSize: 6.5, color: C.teallt, fontFace: "Calibri", align: "center", italic: true, margin: 0
});
}
// ────────────────────────────────────────────────────────────────────────
// SLIDE 8 - COMPARISON TABLE: ACUTE vs CHRONIC
// ────────────────────────────────────────────────────────────────────────
{
let slide = pres.addSlide();
addHeader(slide, "ACUTE vs CHRONIC OSTEOMYELITIS — COMPARISON TABLE", "All Sources");
slide.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 0.85, w: 12.95, h: 0.3, fill: { color: C.navy }, line: { color: C.navy } });
slide.addText("COMPREHENSIVE COMPARISON: ACUTE vs CHRONIC OSTEOMYELITIS", {
x: 0.15, y: 0.85, w: 12.95, h: 0.3, fontSize: 11, bold: true, color: C.white, fontFace: "Calibri", align: "center", margin: 0
});
const compareRows = [
["Feature", "ACUTE OSTEOMYELITIS", "CHRONIC OSTEOMYELITIS"],
["Duration", "< 2 weeks (inflammatory changes present)", "> 6 weeks (bone destruction + sequestra)"],
["Pathology", "Neutrophilic infiltrate, bone/marrow necrosis, abscess formation", "Sequestrum, involucrum, marrow fibrosis, lymphocytes + plasma cells"],
["Organisms", "S. aureus (mainly); age-specific (see microbiology)", "S. aureus, polymicrobial (especially post-traumatic)"],
["Systemic Symptoms", "High fever, rigors, malaise, appear toxic", "Low-grade or absent; chronic draining sinus"],
["Local Signs", "Point tenderness, swelling, warmth, erythema", "Sinus tracts, palpable sequestrum/involucrum"],
["X-ray", "Often NORMAL initially; only soft tissue swelling\n(lag of 10–21 days!)", "Sequestrum, involucrum, 'bone-within-bone', sclerosis, cortical destruction"],
["MRI", "High T2/STIR marrow signal; rim enhancement of abscess", "Low signal sequestrum; ring enhancement; intramedullary changes"],
["Bone Scan", "Hot (3-phase positive)", "May be falsely negative (avascular area)"],
["Treatment", "IV antibiotics ± aspiration/drainage; switch to oral when improving", "Debridement + sequestrectomy + long-course antibiotics + reconstruction"],
["Duration of Abx", "4–6 weeks (can shorten if improving)", "6–12 weeks; may need indefinite suppressive therapy"],
["Prognosis", "Good if treated promptly; 5–25% fail to resolve → chronic", "Flares after years; risk of amyloidosis, SCC, sarcoma; amputation sometimes needed"],
["Special Forms", "Haematogenous (children), post-traumatic (adults)", "Brodie abscess (subacute); Cierny-Mader staging used here"],
];
const cColW = [2.5, 5.2, 5.2];
let cCurY = 1.18;
compareRows.forEach((row, ri) => {
let cCurX = 0.15;
const isH = ri === 0;
const rH = isH ? 0.32 : (ri >= 6 && ri <= 7 ? 0.52 : 0.38);
row.forEach((cell, ci) => {
let bg;
if (isH) {
bg = ci === 0 ? C.navy : (ci === 1 ? C.teal : C.orange);
} else {
bg = ci === 0 ? C.ltgray : (ci === 1 ? (ri % 2 === 0 ? "E3F2F7" : C.white) : (ri % 2 === 0 ? "FFF3E0" : C.white));
}
slide.addShape(pres.shapes.RECTANGLE, { x: cCurX, y: cCurY, w: cColW[ci], h: rH, fill: { color: bg }, line: { color: C.teallt, pt: 0.5 } });
slide.addText(cell, {
x: cCurX + 0.06, y: cCurY, w: cColW[ci] - 0.12, h: rH,
fontSize: isH ? 10 : 8,
bold: isH || ci === 0,
color: isH ? C.white : (ci === 0 ? C.navy : C.dark),
fontFace: "Calibri",
valign: "middle"
});
cCurX += cColW[ci];
});
cCurY += rH;
});
// Bottom note
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 0.15, y: 6.9, w: 12.95, h: 0.38, fill: { color: "FFF3CD" }, line: { color: C.gold, pt: 1.5 }, rectRadius: 0.05 });
slide.addText([
{ text: "★ KEY EXAM PEARL: ", options: { bold: true, color: C.orange } },
{ text: "X-ray in acute osteomyelitis is NORMAL for the first 10–21 days — periosteal reaction and lytic changes appear only AFTER significant bone destruction. MRI is the gold standard for early diagnosis. ESR may remain elevated even after clinical improvement — use CRP to monitor treatment response.", options: { color: C.dark } }
], { x: 0.25, y: 6.93, w: 12.75, h: 0.32, fontSize: 8.5, fontFace: "Calibri", valign: "middle" });
}
// ────────────────────────────────────────────────────────────────────────
// Save
// ────────────────────────────────────────────────────────────────────────
pres.writeFile({ fileName: "/home/daytona/workspace/osteomyelitis-poster/Osteomyelitis_Exam_Poster.pptx" })
.then(() => console.log("✅ Poster saved successfully!"))
.catch(err => { console.error("❌ Error:", err); process.exit(1); });