~/bone-tumour-ppt/create_pptx.js
"use strict";
const pptxgen = require("pptxgenjs");
const { execSync } = require("child_process");
// ─────────────────────────────────────────────
// FETCH ALL IMAGES
// ─────────────────────────────────────────────
const imageUrls = [
"https://cdn.orris.care/cdss_images/1931e4704e30d98d4cd05b93b23b285ec4056df46696c218d5a5c585368de339.png", // 0: moth-eaten
"https://cdn.orris.care/cdss_images/f72615b6395361f05fa7d2039d5b7fd2bc6b0b569b40b519a83f8619c70efaa4.png", // 1: permeative / Ewing
"https://cdn.orris.care/cdss_images/50fe7f8535926b406027655d7487896f9b059916e95d1213680f4510c44f6128.png", // 2: types of periosteal reaction (6-panel)
"https://cdn.orris.care/cdss_images/fb01dd2c5314c9ad91c4e00ef37d65990b25c5ec39675ca6071cf2ec3bc7645b.png", // 3: types of matrix mineralisation (4-panel)
"https://cdn.orris.care/cdss_images/393983627f910dbe2890e4171c6754c66b496a5b5bb49f34427b6303fced4c9a.png", // 4: osteosarcoma Codman triangle X-ray
"https://cdn.orris.care/cdss_images/30c8480a7f30bce53774d5e9ad4323fcd0eab819c9a6ca6421bec20de23f6393.png", // 5: Ewing sarcoma histology
"https://cdn.orris.care/cdss_images/742403518580f55469d5430f44196b49e177c6aaba2ead57140504f2cebd10bb.png", // 6: osteoid osteoma histology
"https://cdn.orris.care/cdss_images/3f2ced7728cf7a6fbf05b43daadd23ed542a55745ac2911e7a835e753213dc4f.png", // 7: chondrosarcoma gross+histo
"https://cdn.orris.care/cdss_images/59969355145da96ff7d45f3bb1e202993c1b6e70a24810e38476aef4a283b080.png", // 8: clear cell chondrosarcoma hip X-ray
"https://cdn.orris.care/cdss_images/6f23f9305fb931f4bfc24c17ee2e15f3095932325f0d0c8655f7628ab82b2ad5.png", // 9: osteosarcoma 3-panel knee X-ray
];
console.log("Fetching images...");
const fetchedRaw = execSync(
`node /home/daytona/skills/shared/scripts/fetch_images.js ${imageUrls.map(u => `"${u}"`).join(" ")}`,
{ maxBuffer: 100 * 1024 * 1024 }
).toString();
const imgs = JSON.parse(fetchedRaw);
console.log(`Fetched ${imgs.filter(i => !i.error).length}/${imgs.length} images OK`);
// ─────────────────────────────────────────────
// COLOUR PALETTE (deep navy + bone white + amber accent)
// ─────────────────────────────────────────────
const C = {
navy: "0D1B2A", // dominant dark
navyMid: "1A2E45", // mid dark panel
navyLight: "1E3A52", // card bg
amber: "E8A020", // accent / highlights
amberLight: "F5C060", // secondary accent
white: "FFFFFF",
offWhite: "F0F4F8",
lightGray: "B0BEC5",
teal: "2E9CCA", // info colour
red: "E53935", // malignant
green: "43A047", // benign
purple: "7B1FA2", // intermediate
slideW: 10,
slideH: 5.625,
};
// ─────────────────────────────────────────────
// HELPERS
// ─────────────────────────────────────────────
function addSlideBg(slide, color) {
slide.background = { color };
}
function addTopBar(slide, title, subtitle) {
// Dark accent bar at top
slide.addShape(pres.shapes.RECTANGLE, {
x: 0, y: 0, w: C.slideW, h: 0.95,
fill: { color: C.navyMid }, line: { color: C.navyMid }
});
// Amber left accent
slide.addShape(pres.shapes.RECTANGLE, {
x: 0, y: 0, w: 0.12, h: 0.95,
fill: { color: C.amber }, line: { color: C.amber }
});
slide.addText(title, {
x: 0.22, y: 0, w: 7.5, h: 0.95, margin: 0,
fontSize: 20, bold: true, color: C.white,
fontFace: "Calibri", valign: "middle"
});
if (subtitle) {
slide.addText(subtitle, {
x: 7.8, y: 0, w: 2.1, h: 0.95, margin: 0,
fontSize: 10, color: C.amberLight,
fontFace: "Calibri", valign: "middle", align: "right"
});
}
}
function addFooter(slide, source) {
slide.addShape(pres.shapes.RECTANGLE, {
x: 0, y: 5.35, w: C.slideW, h: 0.275,
fill: { color: C.navy }, line: { color: C.navy }
});
slide.addText(`Source: ${source}`, {
x: 0.2, y: 5.35, w: 9.6, h: 0.275, margin: 0,
fontSize: 8, color: C.lightGray, fontFace: "Calibri",
valign: "middle", italic: true
});
}
function badge(slide, text, x, y, color) {
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
x, y, w: 1.5, h: 0.3,
fill: { color }, line: { color }, rectRadius: 0.05
});
slide.addText(text, {
x, y, w: 1.5, h: 0.3, margin: 0,
fontSize: 9, bold: true, color: C.white,
fontFace: "Calibri", align: "center", valign: "middle"
});
}
function infoCard(slide, x, y, w, h, title, lines, titleColor) {
slide.addShape(pres.shapes.RECTANGLE, {
x, y, w, h,
fill: { color: C.navyLight }, line: { color: C.amber, pt: 1 },
shadow: { type: "outer", color: "000000", blur: 5, offset: 2, angle: 135, opacity: 0.2 }
});
slide.addText(title, {
x: x + 0.08, y: y + 0.06, w: w - 0.16, h: 0.28, margin: 0,
fontSize: 10, bold: true, color: titleColor || C.amber, fontFace: "Calibri"
});
const bulletItems = lines.map((l, i) => ({
text: l,
options: { bullet: true, breakLine: i < lines.length - 1 }
}));
slide.addText(bulletItems, {
x: x + 0.08, y: y + 0.34, w: w - 0.16, h: h - 0.42, margin: 0,
fontSize: 9, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
}
// ─────────────────────────────────────────────
// PRESENTATION SETUP
// ─────────────────────────────────────────────
const pres = new pptxgen();
pres.layout = "LAYOUT_16x9";
pres.title = "Bone Tumour Imaging Patterns";
pres.author = "Medical Education";
pres.subject = "Radiology / Orthopaedic Pathology";
// ═══════════════════════════════════════════════
// SLIDE 1 — TITLE SLIDE
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
// Diagonal accent strip
s.addShape(pres.shapes.RECTANGLE, {
x: -0.5, y: 3.5, w: 11, h: 0.08,
fill: { color: C.amber }, line: { color: C.amber }
});
// Title block
s.addShape(pres.shapes.RECTANGLE, {
x: 0.4, y: 1.1, w: 9.2, h: 0.06,
fill: { color: C.amber }, line: { color: C.amber }
});
s.addText("BONE TUMOUR", {
x: 0.4, y: 0.55, w: 9.2, h: 0.9, margin: 0,
fontSize: 44, bold: true, color: C.white,
fontFace: "Calibri", charSpacing: 4, align: "left"
});
s.addText("IMAGING PATTERNS", {
x: 0.4, y: 1.2, w: 9.2, h: 0.85, margin: 0,
fontSize: 44, bold: true, color: C.amber,
fontFace: "Calibri", charSpacing: 4, align: "left"
});
s.addText("A Systematic Approach to Radiological Diagnosis", {
x: 0.4, y: 2.1, w: 9.2, h: 0.5, margin: 0,
fontSize: 18, color: C.lightGray, fontFace: "Calibri", align: "left"
});
// Cards at bottom
const topics = [
{ t: "01 Bone Destruction", c: C.teal },
{ t: "02 Periosteal Reaction", c: C.amber },
{ t: "03 Matrix Mineralisation", c: C.red },
{ t: "04 Tumour-Specific Patterns", c: C.green },
{ t: "05 Key Differentials", c: C.purple },
];
topics.forEach((tp, i) => {
s.addShape(pres.shapes.RECTANGLE, {
x: 0.4 + i * 1.86, y: 2.9, w: 1.7, h: 0.55,
fill: { color: tp.c + "33" }, line: { color: tp.c, pt: 1.5 }
});
s.addText(tp.t, {
x: 0.4 + i * 1.86, y: 2.9, w: 1.7, h: 0.55, margin: 0,
fontSize: 8.5, bold: true, color: C.white,
fontFace: "Calibri", align: "center", valign: "middle"
});
});
s.addText("Grainger & Allison's Diagnostic Radiology • Robbins & Kumar Basic Pathology", {
x: 0.4, y: 5.1, w: 9.2, h: 0.3, margin: 0,
fontSize: 9, color: C.lightGray, fontFace: "Calibri", italic: true
});
}
// ═══════════════════════════════════════════════
// SLIDE 2 — WHO CLASSIFICATION OVERVIEW
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "WHO Classification of Bone Tumours (2013)", "Overview");
// Three behaviour columns
const cols = [
{ title: "BENIGN", color: C.green, x: 0.2, items: [
"Osteoid Osteoma", "Osteoblastoma", "Osteochondroma",
"Enchondroma", "Chondroblastoma", "Giant Cell Tumour*",
"Haemangioma", "Aneurysmal Bone Cyst", "Unicameral Bone Cyst",
"Non-ossifying Fibroma"
]},
{ title: "INTERMEDIATE", color: C.amber, x: 3.45, items: [
"Giant Cell Tumour of Bone", "Chondroblastoma",
"Haemangioendothelioma", "Haemangiopericytoma",
"Desmoplastic Fibroma",
"", "* Locally aggressive,", " rarely metastasises"
]},
{ title: "MALIGNANT", color: C.red, x: 6.7, items: [
"Osteosarcoma", "Chondrosarcoma", "Ewing Sarcoma",
"Fibrosarcoma", "Multiple Myeloma",
"Lymphoma of Bone", "Chordoma",
"Undifferentiated Pleomorphic Sarcoma", "Angiosarcoma"
]},
];
cols.forEach(col => {
// Header
s.addShape(pres.shapes.RECTANGLE, {
x: col.x, y: 1.05, w: 3.1, h: 0.42,
fill: { color: col.color }, line: { color: col.color }
});
s.addText(col.title, {
x: col.x, y: 1.05, w: 3.1, h: 0.42, margin: 0,
fontSize: 13, bold: true, color: C.white,
fontFace: "Calibri", align: "center", valign: "middle"
});
// Body
s.addShape(pres.shapes.RECTANGLE, {
x: col.x, y: 1.47, w: 3.1, h: 3.7,
fill: { color: C.navyLight }, line: { color: col.color, pt: 1 }
});
const bulletItems = col.items.map((item, i) => ({
text: item,
options: { bullet: item.startsWith("*") || item.startsWith(" ") ? false : true, breakLine: i < col.items.length - 1, fontSize: 9.5 }
}));
s.addText(bulletItems, {
x: col.x + 0.1, y: 1.52, w: 2.9, h: 3.6, margin: 0,
fontSize: 9.5, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
});
addFooter(s, "WHO 2013 Classification of Bone Tumours | Grainger & Allison's Diagnostic Radiology");
}
// ═══════════════════════════════════════════════
// SLIDE 3 — APPROACH TO BONE LESION ON X-RAY
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Systematic Approach to a Bone Lesion on Plain Radiograph", "Step-by-Step");
const steps = [
{ n: "1", title: "Where is the lesion?", color: C.teal,
lines: ["Epiphysis / Physis / Metaphysis / Diaphysis", "Which bone? Axial vs appendicular", "Cortical / Medullary / Periosteal / Parosteal"] },
{ n: "2", title: "What is it doing to bone?", color: C.amber,
lines: ["Geographic lysis (well-defined)", "Moth-eaten (ill-defined foci)", "Permeative (diffuse infiltration)"] },
{ n: "3", title: "What is bone doing back?", color: C.red,
lines: ["Solid / Laminated / Codman triangle", "Sunburst / Spiculated", "Hair-on-end periosteal reaction"] },
{ n: "4", title: "Matrix mineralisation?", color: C.green,
lines: ["Chondroid — rings & arcs", "Osteoid — cloud-like / ivory", "Ground-glass / Non-specific"] },
{ n: "5", title: "Host factors?", color: C.purple,
lines: ["Patient age (most important!)", "Number of lesions — solitary vs multiple", "Soft-tissue mass? Cortical breach?"] },
];
steps.forEach((st, i) => {
const col = i < 3 ? i : i - 3;
const row = i < 3 ? 0 : 1;
const w = 3.1;
const x = i < 3 ? 0.18 + i * 3.25 : 1.68 + col * 3.25;
const y = 1.1 + row * 2.2;
const h = 1.9;
s.addShape(pres.shapes.RECTANGLE, {
x, y, w, h,
fill: { color: C.navyLight }, line: { color: st.color, pt: 1.5 },
shadow: { type: "outer", color: "000000", blur: 4, offset: 2, angle: 135, opacity: 0.2 }
});
// Number badge
s.addShape(pres.shapes.RECTANGLE, {
x, y, w: 0.36, h,
fill: { color: st.color }, line: { color: st.color }
});
s.addText(st.n, {
x, y, w: 0.36, h, margin: 0,
fontSize: 18, bold: true, color: C.white,
fontFace: "Calibri", align: "center", valign: "middle"
});
s.addText(st.title, {
x: x + 0.44, y: y + 0.06, w: w - 0.5, h: 0.34, margin: 0,
fontSize: 10, bold: true, color: st.color, fontFace: "Calibri"
});
const bulletItems = st.lines.map((l, li) => ({
text: l,
options: { bullet: true, breakLine: li < st.lines.length - 1, fontSize: 9 }
}));
s.addText(bulletItems, {
x: x + 0.44, y: y + 0.42, w: w - 0.5, h: h - 0.5, margin: 0,
fontSize: 9, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
});
// Reminder box
s.addShape(pres.shapes.RECTANGLE, {
x: 5.0, y: 3.3, w: 4.8, h: 1.9,
fill: { color: C.navyMid }, line: { color: C.amber, pt: 1.5 }
});
s.addText("Clinical Context is King", {
x: 5.1, y: 3.35, w: 4.6, h: 0.35, margin: 0,
fontSize: 11, bold: true, color: C.amber, fontFace: "Calibri"
});
const clinicalTips = [
{ text: "Age is the single most powerful discriminator", options: { bullet: true, breakLine: true, fontSize: 9 } },
{ text: "Night pain + young patient → Osteoid osteoma", options: { bullet: true, breakLine: true, fontSize: 9 } },
{ text: "ESR >100 + elderly → Multiple myeloma until proven otherwise", options: { bullet: true, breakLine: true, fontSize: 9 } },
{ text: "Known malignancy → metastasis before primary tumour", options: { bullet: true, fontSize: 9 } },
];
s.addText(clinicalTips, {
x: 5.1, y: 3.72, w: 4.6, h: 1.4, margin: 0,
fontSize: 9, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology, Chapter 40 — General Characteristics of Bone Tumours");
}
// ═══════════════════════════════════════════════
// SLIDE 4 — PATTERNS OF BONE DESTRUCTION
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Patterns of Bone Destruction", "Lüdloff / Lodwick Classification");
// Left: moth-eaten image
if (!imgs[0].error) {
s.addImage({ data: imgs[0].base64, x: 0.2, y: 1.1, w: 2.8, h: 2.2,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Moth-Eaten Pattern (Type IB)", {
x: 0.2, y: 3.32, w: 2.8, h: 0.25, margin: 0,
fontSize: 8.5, bold: true, color: C.amber, fontFace: "Calibri", align: "center"
});
s.addText("Primary bone lymphoma — distal femur", {
x: 0.2, y: 3.57, w: 2.8, h: 0.22, margin: 0,
fontSize: 8, color: C.lightGray, fontFace: "Calibri", align: "center", italic: true
});
// Right: permeative image
if (!imgs[1].error) {
s.addImage({ data: imgs[1].base64, x: 3.2, y: 1.1, w: 3.7, h: 2.2,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Permeative Pattern (Type IC) — Ewing Sarcoma", {
x: 3.2, y: 3.32, w: 3.7, h: 0.25, margin: 0,
fontSize: 8.5, bold: true, color: C.red, fontFace: "Calibri", align: "center"
});
s.addText("Multilaminated periosteal response + cortical erosion + soft tissue mass", {
x: 3.2, y: 3.57, w: 3.7, h: 0.25, margin: 0,
fontSize: 8, color: C.lightGray, fontFace: "Calibri", align: "center", italic: true
});
// Right info panel
const rows = [
{ type: "Type IA — Geographic", desc: "Large well-defined lytic hole with sclerotic margin. Slow-growing, usually BENIGN. e.g. Non-ossifying fibroma, ABC", color: C.green },
{ type: "Type IB — Moth-Eaten", desc: "Multiple ill-defined holes coalescing. Indeterminate — aggressive benign or low-grade malignant. e.g. Lymphoma", color: C.amber },
{ type: "Type IC — Permeative", desc: "Innumerable tiny holes merging imperceptibly with normal bone. MALIGNANT until proven otherwise. e.g. Ewing, Myeloma", color: C.red },
];
rows.forEach((row, i) => {
const y = 1.1 + i * 1.0;
s.addShape(pres.shapes.RECTANGLE, {
x: 7.1, y, w: 2.7, h: 0.9,
fill: { color: C.navyLight }, line: { color: row.color, pt: 1 }
});
s.addShape(pres.shapes.RECTANGLE, { x: 7.1, y, w: 0.1, h: 0.9, fill: { color: row.color }, line: { color: row.color } });
s.addText(row.type, {
x: 7.25, y: y + 0.05, w: 2.5, h: 0.25, margin: 0,
fontSize: 9, bold: true, color: row.color, fontFace: "Calibri"
});
s.addText(row.desc, {
x: 7.25, y: y + 0.3, w: 2.5, h: 0.56, margin: 0,
fontSize: 8, color: C.offWhite, fontFace: "Calibri"
});
});
s.addShape(pres.shapes.RECTANGLE, { x: 7.1, y: 4.12, w: 2.7, h: 1.0, fill: { color: C.navyMid }, line: { color: C.teal, pt: 1 } });
s.addText("Remember", {
x: 7.2, y: 4.14, w: 2.5, h: 0.28, margin: 0,
fontSize: 9, bold: true, color: C.teal, fontFace: "Calibri"
});
s.addText("Lodwick classification gives >90% accuracy in predicting benign vs malignant when combined with periosteal reaction analysis.", {
x: 7.2, y: 4.42, w: 2.5, h: 0.65, margin: 0,
fontSize: 8, color: C.offWhite, fontFace: "Calibri"
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology, Fig. 40.2–40.3 | Lodwick Classification");
}
// ═══════════════════════════════════════════════
// SLIDE 5 — TYPES OF PERIOSTEAL REACTION
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Types of Periosteal Reaction", "Aggressive vs Non-Aggressive");
// Large 6-panel image
if (!imgs[2].error) {
s.addImage({ data: imgs[2].base64, x: 0.15, y: 1.05, w: 5.6, h: 4.0,
shadow: { type: "outer", color: "000000", blur: 8, offset: 3, angle: 135, opacity: 0.35 } });
}
s.addText("Fig. 40.4 — Types of Periosteal Reaction (Grainger & Allison)", {
x: 0.15, y: 5.05, w: 5.6, h: 0.22, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
// Right panel — table of types
const types = [
{ pattern: "Solid / Smooth", behaviour: "Non-aggressive", assoc: "Osteoid osteoma, stress #", color: C.green },
{ pattern: "Laminated (Onion-skin)", behaviour: "Aggressive", assoc: "Ewing sarcoma, Osteosarcoma", color: C.amber },
{ pattern: "Codman Triangle", behaviour: "Highly Aggressive", assoc: "Osteosarcoma, Ewing sarcoma", color: C.red },
{ pattern: "Sunburst / Spiculated", behaviour: "Highly Aggressive", assoc: "Osteosarcoma", color: C.red },
{ pattern: "Hair-on-End", behaviour: "Aggressive", assoc: "Sarcoma, Thalassaemia", color: C.amber },
{ pattern: "Eggshell (thin rim)", behaviour: "Slow-growing", assoc: "GCT, ABC, enchondroma", color: C.teal },
];
// Column headers
s.addShape(pres.shapes.RECTANGLE, {
x: 5.95, y: 1.05, w: 3.85, h: 0.35,
fill: { color: C.navyMid }, line: { color: C.amber, pt: 1 }
});
["Pattern", "Behaviour", "Associated Tumour"].forEach((h, i) => {
s.addText(h, {
x: 5.95 + i * 1.28, y: 1.05, w: 1.28, h: 0.35, margin: 0,
fontSize: 8.5, bold: true, color: C.amber,
fontFace: "Calibri", align: "center", valign: "middle"
});
});
types.forEach((row, i) => {
const y = 1.42 + i * 0.6;
const bg = i % 2 === 0 ? C.navyLight : C.navyMid;
s.addShape(pres.shapes.RECTANGLE, {
x: 5.95, y, w: 3.85, h: 0.56,
fill: { color: bg }, line: { color: C.navyMid }
});
s.addShape(pres.shapes.RECTANGLE, { x: 5.95, y, w: 0.05, h: 0.56, fill: { color: row.color }, line: { color: row.color } });
s.addText(row.pattern, {
x: 6.02, y, w: 1.24, h: 0.56, margin: 0,
fontSize: 8.5, bold: true, color: C.offWhite, fontFace: "Calibri", valign: "middle"
});
s.addText(row.behaviour, {
x: 7.23, y, w: 1.28, h: 0.56, margin: 0,
fontSize: 8.5, color: row.color, fontFace: "Calibri", align: "center", valign: "middle", bold: true
});
s.addText(row.assoc, {
x: 8.52, y, w: 1.28, h: 0.56, margin: 0,
fontSize: 8, color: C.lightGray, fontFace: "Calibri", valign: "middle"
});
});
s.addShape(pres.shapes.RECTANGLE, {
x: 5.95, y: 4.9, w: 3.85, h: 0.42,
fill: { color: C.navyMid }, line: { color: C.red, pt: 1 }
});
s.addText("Codman triangle and sunburst = ALWAYS malignant until proven otherwise", {
x: 6.05, y: 4.9, w: 3.65, h: 0.42, margin: 0,
fontSize: 9, bold: true, color: C.red, fontFace: "Calibri", valign: "middle"
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology, Fig. 40.4 — Types of Periosteal Reaction");
}
// ═══════════════════════════════════════════════
// SLIDE 6 — MATRIX MINERALISATION
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Matrix Mineralisation Patterns", "Key to Histological Subtype");
if (!imgs[3].error) {
s.addImage({ data: imgs[3].base64, x: 0.15, y: 1.05, w: 6.0, h: 4.05,
shadow: { type: "outer", color: "000000", blur: 8, offset: 3, angle: 135, opacity: 0.35 } });
}
s.addText("Fig. 40.5 — Types of Matrix Mineralisation (Grainger & Allison)", {
x: 0.15, y: 5.1, w: 6.0, h: 0.22, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
// Panel labels overlay on image (A/B/C/D)
[["A", 0.2, 1.1], ["B", 3.2, 1.1], ["C", 0.2, 3.15], ["D", 3.2, 3.15]].forEach(([lbl, x, y]) => {
s.addShape(pres.shapes.RECTANGLE, {
x, y, w: 0.28, h: 0.28,
fill: { color: C.amber + "CC" }, line: { color: C.amber }
});
s.addText(lbl, {
x, y, w: 0.28, h: 0.28, margin: 0,
fontSize: 11, bold: true, color: C.navy,
fontFace: "Calibri", align: "center", valign: "middle"
});
});
const matrixTypes = [
{ lbl: "A — Chondroid", desc: "Rings & arcs / nodular calcification. Lobular hyaline cartilage. Classic for enchondroma & chondrosarcoma.", color: C.teal, y: 1.05 },
{ lbl: "B — Osteoid", desc: "Dense 'cloud-like', ivory or amorphous calcification. Classic for osteosarcoma and osteoblastoma.", color: C.amber, y: 2.3 },
{ lbl: "C — Ground Glass", desc: "Diffuse smudged opacity filling medullary canal. Pathognomonic of fibrous dysplasia.", color: C.green, y: 3.55 },
{ lbl: "D — Non-specific", desc: "Punctate / stippled or no mineralisation. Common in many tumours; non-diagnostic alone.", color: C.lightGray, y: 4.7 },
];
matrixTypes.forEach(mt => {
s.addShape(pres.shapes.RECTANGLE, {
x: 6.35, y: mt.y, w: 3.45, h: 1.1,
fill: { color: C.navyLight }, line: { color: mt.color, pt: 1 }
});
s.addText(mt.lbl, {
x: 6.45, y: mt.y + 0.06, w: 3.2, h: 0.28, margin: 0,
fontSize: 10, bold: true, color: mt.color, fontFace: "Calibri"
});
s.addText(mt.desc, {
x: 6.45, y: mt.y + 0.36, w: 3.25, h: 0.7, margin: 0,
fontSize: 9, color: C.offWhite, fontFace: "Calibri"
});
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology, Fig. 40.5 — Types of Matrix Mineralisation");
}
// ═══════════════════════════════════════════════
// SLIDE 7 — OSTEOSARCOMA IMAGING
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Osteosarcoma — Imaging Features", "Most Common Primary Malignant Bone Tumour");
badge(s, "MALIGNANT", 8.9, 0.12, C.red);
// 2 images side by side
if (!imgs[9].error) {
s.addImage({ data: imgs[9].base64, x: 0.2, y: 1.05, w: 4.1, h: 2.8,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Fig. 41.27 — Lytic, mixed, and sclerotic osteosarcoma variants (Grainger & Allison)", {
x: 0.2, y: 3.87, w: 4.1, h: 0.25, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
if (!imgs[4].error) {
s.addImage({ data: imgs[4].base64, x: 4.5, y: 1.05, w: 2.3, h: 2.8,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Codman Triangle — distal femur (Robbins Fig. 19.15)", {
x: 4.5, y: 3.87, w: 2.3, h: 0.25, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
// Right column info
const features = [
{ head: "Epidemiology", body: "Most common non-haematopoietic primary bone malignancy. Bimodal: peak 10-14 yrs; 2nd peak elderly (Paget's). Male > Female (1.35:1).", color: C.teal },
{ head: "Location", body: "Metaphysis of growing long bones — distal femur (50%), proximal tibia, proximal humerus. Diaphyseal <10%.", color: C.amber },
{ head: "Imaging Features", body: "Moth-eaten / permeative destruction. Mixed lytic-sclerotic. Cloud-like osteoid matrix. Codman triangle or sunburst periosteal reaction. Soft tissue mass.", color: C.red },
{ head: "MRI Staging (Mandatory)", body: "Defines medullary/soft-tissue extent. Neurovascular involvement. Whole bone to exclude skip metastases. Joint involvement.", color: C.green },
];
features.forEach((f, i) => {
const y = 1.05 + i * 1.05;
s.addShape(pres.shapes.RECTANGLE, {
x: 6.95, y, w: 2.85, h: 1.0,
fill: { color: C.navyLight }, line: { color: f.color, pt: 1 }
});
s.addShape(pres.shapes.RECTANGLE, { x: 6.95, y, w: 0.08, h: 1.0, fill: { color: f.color }, line: { color: f.color } });
s.addText(f.head, {
x: 7.07, y: y + 0.06, w: 2.67, h: 0.25, margin: 0,
fontSize: 9, bold: true, color: f.color, fontFace: "Calibri"
});
s.addText(f.body, {
x: 7.07, y: y + 0.3, w: 2.67, h: 0.65, margin: 0,
fontSize: 8.5, color: C.offWhite, fontFace: "Calibri"
});
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology, Chapter 41 | Robbins & Kumar Basic Pathology");
}
// ═══════════════════════════════════════════════
// SLIDE 8 — EWING SARCOMA IMAGING & HISTOLOGY
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Ewing Sarcoma — Imaging & Histology", "Commonest Bone Sarcoma in Children < 10 yrs");
badge(s, "MALIGNANT", 8.9, 0.12, C.red);
if (!imgs[1].error) {
s.addImage({ data: imgs[1].base64, x: 0.2, y: 1.05, w: 4.5, h: 2.7,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Permeative pattern + onion-skin periosteal reaction + soft-tissue mass", {
x: 0.2, y: 3.77, w: 4.5, h: 0.25, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
if (!imgs[5].error) {
s.addImage({ data: imgs[5].base64, x: 4.85, y: 1.05, w: 2.4, h: 2.7,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Histology: sheets of small round blue cells (Robbins Fig. 19.23)", {
x: 4.85, y: 3.77, w: 2.4, h: 0.25, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
// Info card
infoCard(s, 7.45, 1.05, 2.35, 4.1, "Key Facts",
[
"Age: 5–20 yrs (peak)",
"Location: DIAPHYSIS of long bones; pelvis",
"X-ray: permeative lysis + onion-skin or Codman",
"MRI: large extraosseous soft-tissue mass",
"Genetics: t(11;22) — EWSR1-FLI1 fusion",
"Histology: small round blue cells",
"Treatment: chemo + surgery ± RT",
"Prognosis: ~75% 5-yr survival",
], C.red);
// Pearls
s.addShape(pres.shapes.RECTANGLE, {
x: 0.2, y: 4.08, w: 7.1, h: 1.17,
fill: { color: C.navyMid }, line: { color: C.amber, pt: 1 }
});
s.addText("Teaching Pearls", {
x: 0.3, y: 4.1, w: 3, h: 0.28, margin: 0,
fontSize: 10, bold: true, color: C.amber, fontFace: "Calibri"
});
const pearls = [
{ text: "Ewing mimics osteomyelitis clinically (fever, raised ESR) — always consider in diaphyseal lesions in children", options: { bullet: true, breakLine: true, fontSize: 9 } },
{ text: "20% of Ewing sarcoma is extraskeletal — can arise in soft tissue", options: { bullet: true, breakLine: true, fontSize: 9 } },
{ text: "Codman triangle in Ewing = aggressive periosteal reaction, NOT pathognomonic of osteosarcoma", options: { bullet: true, fontSize: 9 } },
];
s.addText(pearls, {
x: 0.3, y: 4.4, w: 6.9, h: 0.82, margin: 0,
fontSize: 9, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology, Fig. 40.3 | Robbins & Kumar Basic Pathology, Fig. 19.23");
}
// ═══════════════════════════════════════════════
// SLIDE 9 — CHONDROSARCOMA IMAGING & HISTOLOGY
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Chondrosarcoma — Imaging & Histology", "2nd Most Common Primary Malignant Bone Tumour");
badge(s, "MALIGNANT", 8.9, 0.12, C.red);
if (!imgs[8].error) {
s.addImage({ data: imgs[8].base64, x: 0.2, y: 1.05, w: 2.8, h: 2.7,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Chondrosarcoma proximal femur — solid epiphyseal lesion\nNote: differentiates from subchondral geode on MRI", {
x: 0.2, y: 3.77, w: 2.8, h: 0.4, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
if (!imgs[7].error) {
s.addImage({ data: imgs[7].base64, x: 3.2, y: 1.05, w: 4.2, h: 2.7,
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Gross & histology: hyaline cartilage nodules permeating medullary canal & cortex (Robbins Fig. 19.22)", {
x: 3.2, y: 3.77, w: 4.2, h: 0.25, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
infoCard(s, 7.55, 1.05, 2.25, 4.1, "Key Facts",
[
"Age: 40–60 yrs",
"Location: pelvis, proximal femur, shoulder",
"X-ray: lytic + rings/arcs calcification",
"Endosteal scalloping (>2/3 cortex thickness)",
"MRI: lobulated T2-bright cartilage",
"Chemo: NOT effective",
"Treatment: wide surgical excision only",
"Prognosis: grade-dependent (10–90% 5-yr)",
], C.teal);
s.addShape(pres.shapes.RECTANGLE, {
x: 0.2, y: 4.15, w: 7.2, h: 1.1,
fill: { color: C.navyMid }, line: { color: C.teal, pt: 1 }
});
s.addText("Grading", {
x: 0.3, y: 4.17, w: 1, h: 0.28, margin: 0,
fontSize: 10, bold: true, color: C.teal, fontFace: "Calibri"
});
const grades = [
{ text: "Grade 1 (ACT/Low-grade): well-defined, minimal atypia, 90% 5-yr survival", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "Grade 2: moderate cellularity/atypia, intermediate prognosis", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "Grade 3 (High-grade): marked pleomorphism, necrosis, <30% 5-yr survival", options: { bullet: true, fontSize: 8.5 } },
];
s.addText(grades, {
x: 0.3, y: 4.45, w: 6.9, h: 0.76, margin: 0,
fontSize: 8.5, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology, Fig. 41.26 | Robbins & Kumar Basic Pathology, Fig. 19.22");
}
// ═══════════════════════════════════════════════
// SLIDE 10 — OSTEOID OSTEOMA & GIANT CELL TUMOUR
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Benign & Intermediate Tumours — Imaging Patterns", "Osteoid Osteoma | Giant Cell Tumour | Enchondroma");
// --- Osteoid osteoma histology image ---
if (!imgs[6].error) {
s.addImage({ data: imgs[6].base64, x: 0.15, y: 1.05, w: 3.2, h: 2.35,
shadow: { type: "outer", color: "000000", blur: 5, offset: 2, angle: 135, opacity: 0.3 } });
}
s.addText("Osteoid osteoma histology: woven bone trabeculae rimmed by osteoblasts", {
x: 0.15, y: 3.42, w: 3.2, h: 0.25, margin: 0,
fontSize: 7.5, color: C.lightGray, fontFace: "Calibri", italic: true, align: "center"
});
// Osteoid osteoma card
infoCard(s, 0.15, 3.7, 3.2, 1.55, "Osteoid Osteoma",
["Age 10–20 yrs; young men", "Femur/tibia CORTEX (50%)", "Severe night pain — relieved by NSAIDs", "X-ray: round lucent nidus <2cm, dense sclerotic rim", "CT: best for nidus detection", "Rx: RFA or surgical excision"],
C.green);
// GCT card
infoCard(s, 3.55, 1.05, 3.1, 2.25, "Giant Cell Tumour of Bone",
["Age 20–50 yrs; slight female preponderance", "EPIPHYSIS — distal femur / proximal tibia", "X-ray: lytic 'soap bubble' lesion extending to subchondral bone", "MRI: low T2 signal (haemosiderin deposits)", "Cortex expanded, thin shell of reactive bone", "Behaviour: Benign but locally aggressive"],
C.amber);
infoCard(s, 3.55, 3.32, 3.1, 1.93, "Giant Cell Tumour — Pathology",
["Multinucleate osteoclast-type giant cells (up to 100 nuclei)", "Neoplastic cells express high RANKL — drives bone destruction", "Absent feedback between osteoblasts/osteoclasts", "Treatment: curettage ± cement; DENOSUMAB for unresectable", "40% recurrence after curettage; rare lung metastasis"],
C.purple);
// Enchondroma card
infoCard(s, 6.75, 1.05, 3.05, 4.2, "Enchondroma",
[
"Most common bone tumour of the HAND",
"Proximal/middle phalanges & metacarpals",
"Peak: 2nd decade; equal sex distribution",
"X-ray: lytic lesion, may have cartilaginous calcification (rings & arcs)",
"Often INCIDENTAL — asymptomatic",
"Pain / fracture if structural compromise",
"Multiple enchondromatosis = Ollier disease",
"With haemangiomas = Maffucci syndrome (malignant transformation risk!)",
"Rx: curettage + bone graft if symptomatic",
], C.teal);
addFooter(s, "Robbins & Kumar Basic Pathology | Grainger & Allison's Diagnostic Radiology | Bailey & Love 28th Ed");
}
// ═══════════════════════════════════════════════
// SLIDE 11 — LOCATION-BASED DIFFERENTIAL DIAGNOSIS
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Location-Based Differential Diagnosis", "Epiphysis | Metaphysis | Diaphysis");
// Bone diagram outline (simple schematic using shapes)
// Epiphysis block
const sections = [
{ label: "EPIPHYSIS", y: 1.05, color: C.teal, w: 1.2, dx: 0.45,
tumours: ["Giant Cell Tumour", "Chondroblastoma", "Clear Cell Chondrosarcoma", "Intraosseous Ganglion", "Subchondral Geode"] },
{ label: "PHYSIS / GROWTH PLATE", y: 2.12, color: C.amberLight, w: 1.2, dx: 0.45,
tumours: ["Ewing Sarcoma (may cross)", "Osteomyelitis (Brodie abscess)"] },
{ label: "METAPHYSIS", y: 2.75, color: C.amber, w: 1.2, dx: 0.45,
tumours: ["Osteosarcoma (classic)", "Non-ossifying Fibroma", "Aneurysmal Bone Cyst", "Enchondroma", "Simple Bone Cyst", "Osteochondroma"] },
{ label: "DIAPHYSIS", y: 3.95, color: C.red, w: 1.2, dx: 0.45,
tumours: ["Ewing Sarcoma", "Adamantinoma (tibia)", "Multiple Myeloma / Metastasis", "Lymphoma of Bone", "Fibrous Dysplasia"] },
];
// Bone silhouette (simplified)
s.addShape(pres.shapes.RECTANGLE, { x: 0.7, y: 1.05, w: 0.55, h: 0.95, fill: { color: "E8E0D0" }, line: { color: "B0A898", pt: 1.5 } });
s.addShape(pres.shapes.RECTANGLE, { x: 0.65, y: 2.0, w: 0.65, h: 2.05, fill: { color: "D4C8B0" }, line: { color: "B0A898", pt: 1.5 } });
s.addShape(pres.shapes.RECTANGLE, { x: 0.7, y: 4.05, w: 0.55, h: 0.95, fill: { color: "E8E0D0" }, line: { color: "B0A898", pt: 1.5 } });
sections.forEach(sec => {
// Connector line from bone to label
s.addShape(pres.shapes.RECTANGLE, {
x: 0.9 + sec.dx, y: sec.y + 0.1, w: 0.35, h: 0.05,
fill: { color: sec.color }, line: { color: sec.color }
});
s.addShape(pres.shapes.RECTANGLE, {
x: 1.62, y: sec.y, w: 2.0, h: 0.32,
fill: { color: sec.color }, line: { color: sec.color }
});
s.addText(sec.label, {
x: 1.62, y: sec.y, w: 2.0, h: 0.32, margin: 0,
fontSize: 9.5, bold: true, color: C.navy,
fontFace: "Calibri", align: "center", valign: "middle"
});
const bItems = sec.tumours.map((t, i) => ({
text: t,
options: { bullet: true, breakLine: i < sec.tumours.length - 1, fontSize: 9 }
}));
s.addText(bItems, {
x: 1.72, y: sec.y + 0.35, w: 1.8, h: sec.tumours.length * 0.22 + 0.05, margin: 0,
fontSize: 9, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
});
// Right column — age-based table
s.addShape(pres.shapes.RECTANGLE, {
x: 3.9, y: 1.05, w: 5.9, h: 0.42,
fill: { color: C.navyMid }, line: { color: C.amber, pt: 1 }
});
["Age Group", "Likely Diagnosis", "Location", "Key Feature"].forEach((h, i) => {
s.addText(h, {
x: 3.9 + i * 1.47, y: 1.05, w: 1.47, h: 0.42, margin: 0,
fontSize: 8.5, bold: true, color: C.amber, fontFace: "Calibri",
align: "center", valign: "middle"
});
});
const ageRows = [
["< 5 yrs", "Metastatic Neuroblastoma", "Metaphysis", "Multiple lesions; periosteal reaction"],
["5–15 yrs", "Ewing Sarcoma", "Diaphysis", "Onion-skin periosteum; fever"],
["10–20 yrs", "Osteosarcoma", "Metaphysis", "Codman triangle; sunburst"],
["20–40 yrs", "Giant Cell Tumour", "Epiphysis", "Soap bubble; subchondral"],
["40–60 yrs", "Chondrosarcoma", "Pelvis/long bone", "Rings & arcs; endosteal scalloping"],
["> 60 yrs", "Multiple Myeloma", "Axial skeleton", "Punched-out lesions; ESR >100"],
["> 60 yrs", "Metastases", "Any bone", "Multiple lesions; known primary"],
];
ageRows.forEach((row, i) => {
const y = 1.49 + i * 0.52;
const bg = i % 2 === 0 ? C.navyLight : C.navyMid;
s.addShape(pres.shapes.RECTANGLE, {
x: 3.9, y, w: 5.9, h: 0.5,
fill: { color: bg }, line: { color: C.navyMid }
});
row.forEach((cell, j) => {
s.addText(cell, {
x: 3.9 + j * 1.47, y, w: 1.47, h: 0.5, margin: 0,
fontSize: 8.5, color: j === 0 ? C.amberLight : C.offWhite,
fontFace: "Calibri", align: j === 0 ? "center" : "left",
bold: j === 0, valign: "middle"
});
});
});
addFooter(s, "Robbins & Kumar Basic Pathology, Table 19.1 | Grainger & Allison's Diagnostic Radiology | Bailey & Love 28th Ed");
}
// ═══════════════════════════════════════════════
// SLIDE 12 — MRI & STAGING
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "MRI & Multi-modality Imaging — Staging Protocol", "From Plain X-ray to Biopsy");
// Phase-based staging protocol
const phases = [
{ phase: "Phase 1", time: "Within 24 hrs", color: C.teal, x: 0.15, items: [
"Full history & examination", "Blood: FBC, ESR, CRP, ALP, Ca²⁺, PO₄, LFTs, PSA",
"Plain X-ray — whole bone", "Chest X-ray"
]},
{ phase: "Phase 2", time: "Within 1 Week", color: C.amber, x: 3.6, items: [
"Technetium-99 Bone Scan", "Ultrasound abdomen",
"CT Chest (metastasis staging)", "PET-CT (if available)"
]},
{ phase: "Phase 3", time: "Specialist Centre", color: C.red, x: 7.05, items: [
"CT of lesion (cortical detail)", "MRI of lesion — MANDATORY for staging",
"Biopsy (core needle or open)", "Multidisciplinary team review"
]},
];
phases.forEach(ph => {
s.addShape(pres.shapes.RECTANGLE, {
x: ph.x, y: 1.0, w: 2.8, h: 0.42,
fill: { color: ph.color }, line: { color: ph.color }
});
s.addText(`${ph.phase} — ${ph.time}`, {
x: ph.x, y: 1.0, w: 2.8, h: 0.42, margin: 0,
fontSize: 10, bold: true, color: C.navy,
fontFace: "Calibri", align: "center", valign: "middle"
});
s.addShape(pres.shapes.RECTANGLE, {
x: ph.x, y: 1.44, w: 2.8, h: 1.8,
fill: { color: C.navyLight }, line: { color: ph.color, pt: 1 }
});
const bItems = ph.items.map((item, i) => ({
text: item,
options: { bullet: true, breakLine: i < ph.items.length - 1, fontSize: 9 }
}));
s.addText(bItems, {
x: ph.x + 0.1, y: 1.49, w: 2.6, h: 1.7, margin: 0,
fontSize: 9, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
});
// Arrows between phases
[1.42, 4.87].forEach(ax => {
s.addShape(pres.shapes.RECTANGLE, {
x: ax, y: 2.1, w: 0.35, h: 0.1,
fill: { color: C.amber }, line: { color: C.amber }
});
s.addText("▶", {
x: ax - 0.05, y: 2.04, w: 0.4, h: 0.2, margin: 0,
fontSize: 12, color: C.amber, fontFace: "Calibri", align: "center"
});
});
// MRI sequences table
s.addShape(pres.shapes.RECTANGLE, {
x: 0.15, y: 3.35, w: 9.7, h: 0.35,
fill: { color: C.navyMid }, line: { color: C.amber, pt: 1 }
});
s.addText("MRI Sequences in Bone Tumour Assessment", {
x: 0.25, y: 3.35, w: 9.5, h: 0.35, margin: 0,
fontSize: 11, bold: true, color: C.amber, fontFace: "Calibri", valign: "middle"
});
const mriRows = [
["T1W", "Defines marrow extent (low signal = tumour replacing fat)", "Medullary involvement, skip metastases"],
["T2W / STIR", "Tumour bright (fluid/cartilage) — delineates soft-tissue mass", "Extent of soft-tissue component"],
["T1W + Gadolinium", "Distinguishes viable tumour from necrosis/cyst", "Response to chemotherapy"],
["Whole-bone sequence", "Detects skip metastases away from primary lesion", "Mandatory in osteosarcoma"],
["DWI", "Restricted diffusion in malignant lesions", "Characterisation; post-chemo assessment"],
];
mriRows.forEach((row, i) => {
const y = 3.72 + i * 0.32;
const bg = i % 2 === 0 ? C.navyLight : C.navyMid;
s.addShape(pres.shapes.RECTANGLE, { x: 0.15, y, w: 9.7, h: 0.3, fill: { color: bg }, line: { color: bg } });
[row[0], row[1], row[2]].forEach((cell, j) => {
const widths = [1.0, 5.5, 3.15];
const xs = [0.15, 1.2, 6.75];
s.addText(cell, {
x: xs[j], y, w: widths[j], h: 0.3, margin: 0,
fontSize: 8.5, color: j === 0 ? C.teal : C.offWhite,
bold: j === 0, fontFace: "Calibri", valign: "middle"
});
});
});
addFooter(s, "Bailey and Love's Short Practice of Surgery 28th Ed, Table 42.5 | Grainger & Allison's Diagnostic Radiology");
}
// ═══════════════════════════════════════════════
// SLIDE 13 — KEY DIFFERENTIALS AT A GLANCE
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Key Differentials at a Glance — Comparison Table", "Benign vs Malignant Summary");
const headers = ["Feature", "BENIGN", "MALIGNANT"];
const rows = [
["Border / Margin", "Well-defined, sclerotic rim", "Ill-defined, permeative, moth-eaten"],
["Growth rate", "Slow", "Rapid"],
["Cortex", "Intact or smoothly expanded", "Destroyed / breached"],
["Periosteal reaction", "None / solid smooth", "Codman ∆ / Sunburst / Onion-skin"],
["Soft-tissue mass", "Absent", "Common"],
["Matrix", "Dense, organised", "Irregular, amorphous"],
["Metastasis", "None", "Common (lung first site)"],
["Systemic symptoms", "Absent", "Weight loss, fever, anaemia"],
];
// Header row
s.addShape(pres.shapes.RECTANGLE, { x: 0.15, y: 1.0, w: 9.7, h: 0.42, fill: { color: C.navyMid }, line: { color: C.navyMid } });
[["Feature", 0.15, 2.8], ["BENIGN", 2.95, 3.35], ["MALIGNANT", 6.45, 3.4]].forEach(([h, x, w]) => {
const col = h === "BENIGN" ? C.green : h === "MALIGNANT" ? C.red : C.amber;
s.addText(h, {
x, y: 1.0, w, h: 0.42, margin: 0,
fontSize: 12, bold: true, color: col,
fontFace: "Calibri", align: "center", valign: "middle"
});
});
rows.forEach((row, i) => {
const y = 1.44 + i * 0.48;
const bg = i % 2 === 0 ? C.navyLight : C.navyMid;
s.addShape(pres.shapes.RECTANGLE, { x: 0.15, y, w: 9.7, h: 0.46, fill: { color: bg }, line: { color: bg } });
// Feature col
s.addText(row[0], { x: 0.25, y, w: 2.6, h: 0.46, margin: 0, fontSize: 9.5, bold: true, color: C.amberLight, fontFace: "Calibri", valign: "middle" });
// Benign col
s.addText(row[1], { x: 3.0, y, w: 3.3, h: 0.46, margin: 0, fontSize: 9.5, color: C.offWhite, fontFace: "Calibri", valign: "middle" });
// Malignant col
s.addText(row[2], { x: 6.5, y, w: 3.3, h: 0.46, margin: 0, fontSize: 9.5, color: C.offWhite, fontFace: "Calibri", valign: "middle" });
// Coloured dots
s.addShape(pres.shapes.RECTANGLE, { x: 2.97, y: y + 0.14, w: 0.06, h: 0.18, fill: { color: C.green }, line: { color: C.green } });
s.addShape(pres.shapes.RECTANGLE, { x: 6.47, y: y + 0.14, w: 0.06, h: 0.18, fill: { color: C.red }, line: { color: C.red } });
});
addFooter(s, "Grainger & Allison's Diagnostic Radiology | Robbins & Kumar Basic Pathology | Bailey & Love 28th Ed");
}
// ═══════════════════════════════════════════════
// SLIDE 14 — CLINICAL MNEMONICS & SUMMARY
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
addTopBar(s, "Clinical Pearls, Mnemonics & High-Yield Summary", "Examination & Clinical Practice");
// Mnemonic box
s.addShape(pres.shapes.RECTANGLE, {
x: 0.15, y: 1.0, w: 4.6, h: 2.4,
fill: { color: C.navyLight }, line: { color: C.amber, pt: 1.5 }
});
s.addText("Mnemonic: BONE TUMOUR", {
x: 0.25, y: 1.05, w: 4.4, h: 0.34, margin: 0,
fontSize: 11, bold: true, color: C.amber, fontFace: "Calibri"
});
const mnemonic = [
{ text: "B — Bone destruction pattern (Geographic/Moth-eaten/Permeative)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "O — Origin / Location (epiphysis, metaphysis, diaphysis)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "N — Number of lesions (solitary vs multiple)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "E — Edge / margin sharpness", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "T — Tissue of origin (bone / cartilage / fibrous / vascular)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "U — Underpinning host factors (age, Paget's, radiation, genetics)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "M — Matrix mineralisation (chondroid, osteoid, ground glass)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "O — Osseous shell / cortical status", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "U — Use MRI for staging; use CT for cortical detail", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "R — Refer to specialist MDT for biopsy & treatment", options: { bullet: true, fontSize: 8.5 } },
];
s.addText(mnemonic, {
x: 0.25, y: 1.41, w: 4.4, h: 1.95, margin: 0,
fontSize: 8.5, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
// High-yield facts box
s.addShape(pres.shapes.RECTANGLE, {
x: 4.9, y: 1.0, w: 4.9, h: 2.4,
fill: { color: C.navyLight }, line: { color: C.teal, pt: 1.5 }
});
s.addText("High-Yield Exam Facts", {
x: 5.0, y: 1.05, w: 4.7, h: 0.34, margin: 0,
fontSize: 11, bold: true, color: C.teal, fontFace: "Calibri"
});
const facts = [
{ text: "Most common primary malignant bone tumour (excl. haematopoietic) = Osteosarcoma", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "Most common primary malignancy in adults = Multiple Myeloma", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "Most common bone tumour of the hand = Enchondroma", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "Most common benign bone tumour overall = Osteochondroma", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "Codman triangle = NOT pathognomonic of osteosarcoma — seen in any aggressive tumour", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "GCT is the only tumour arising in the epiphysis in adults (after physeal closure)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "Night pain + young + NSAID relief = Osteoid osteoma (prostaglandin-mediated)", options: { bullet: true, breakLine: true, fontSize: 8.5 } },
{ text: "ESR >100 + age >65 + back pain = Multiple myeloma until proven otherwise", options: { bullet: true, fontSize: 8.5 } },
];
s.addText(facts, {
x: 5.0, y: 1.41, w: 4.7, h: 1.95, margin: 0,
fontSize: 8.5, color: C.offWhite, fontFace: "Calibri", valign: "top"
});
// Treatment row
const txCols = [
{ t: "Osteosarcoma", c: "Neo-adj chemo + limb salvage surgery + adj chemo", color: C.red },
{ t: "Ewing Sarcoma", c: "Chemo + excision ± radiotherapy", color: C.amber },
{ t: "Chondrosarcoma", c: "Wide excision only — chemo ineffective", color: C.teal },
{ t: "Giant Cell Tumour", c: "Curettage ± cement; Denosumab if unresectable", color: C.purple },
];
txCols.forEach((tx, i) => {
const x = 0.15 + i * 2.45;
s.addShape(pres.shapes.RECTANGLE, {
x, y: 3.52, w: 2.35, h: 0.35,
fill: { color: tx.color }, line: { color: tx.color }
});
s.addText(tx.t, { x, y: 3.52, w: 2.35, h: 0.35, margin: 0, fontSize: 9, bold: true, color: C.white, fontFace: "Calibri", align: "center", valign: "middle" });
s.addShape(pres.shapes.RECTANGLE, {
x, y: 3.88, w: 2.35, h: 0.72,
fill: { color: C.navyLight }, line: { color: tx.color, pt: 1 }
});
s.addText(tx.c, { x: x + 0.08, y: 3.9, w: 2.2, h: 0.68, margin: 0, fontSize: 9, color: C.offWhite, fontFace: "Calibri", valign: "middle" });
});
s.addShape(pres.shapes.RECTANGLE, {
x: 0.15, y: 4.63, w: 9.7, h: 0.62,
fill: { color: C.navyMid }, line: { color: C.amber, pt: 1 }
});
s.addText([
{ text: "Key Principle: ", options: { bold: true, color: C.amber, fontSize: 10 } },
{ text: "Stop — Think — Investigate. A suspected bone tumour requires high clinical suspicion, prompt investigation, and early MDT referral. Never biopsy before imaging is complete.", options: { color: C.offWhite, fontSize: 10 } }
], { x: 0.3, y: 4.65, w: 9.5, h: 0.58, margin: 0, fontFace: "Calibri", valign: "middle" });
addFooter(s, "Bailey & Love 28th Ed | Robbins & Kumar Basic Pathology | Grainger & Allison's Diagnostic Radiology");
}
// ═══════════════════════════════════════════════
// SLIDE 15 — THANK YOU / REFERENCES
// ═══════════════════════════════════════════════
{
const s = pres.addSlide();
addSlideBg(s, C.navy);
s.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: C.slideW, h: 0.08, fill: { color: C.amber }, line: { color: C.amber } });
s.addShape(pres.shapes.RECTANGLE, { x: 0, y: 5.545, w: C.slideW, h: 0.08, fill: { color: C.amber }, line: { color: C.amber } });
s.addText("Thank You", {
x: 0.5, y: 0.5, w: 9, h: 0.85, margin: 0,
fontSize: 42, bold: true, color: C.white, fontFace: "Calibri", align: "center"
});
s.addText("Bone Tumour Imaging Patterns — A Systematic Teaching Module", {
x: 0.5, y: 1.38, w: 9, h: 0.42, margin: 0,
fontSize: 16, color: C.amber, fontFace: "Calibri", align: "center"
});
s.addShape(pres.shapes.RECTANGLE, { x: 1.5, y: 1.85, w: 7, h: 0.05, fill: { color: C.navyLight }, line: { color: C.navyLight } });
s.addText("References & Sources", {
x: 0.5, y: 2.0, w: 9, h: 0.35, margin: 0,
fontSize: 13, bold: true, color: C.teal, fontFace: "Calibri", align: "center"
});
const refs = [
"1. Grainger & Allison's Diagnostic Radiology: A Textbook of Medical Imaging. Chapters 40 & 41 — General Characteristics of Bone Tumours; Osteosarcoma.",
"2. Robbins & Kumar Basic Pathology (Robbins Pathology). Chapter 19 — Bones, Joints and Soft Tissue Tumours. Table 19.1.",
"3. Bailey and Love's Short Practice of Surgery, 28th Edition. Chapter 42 — Evaluation and Investigation of Bone and Soft-Tissue Tumours. Table 42.5.",
"4. Sabiston Textbook of Surgery, The Biological Basis of Modern Surgical Practice. Chapter 119 — Bone Tumours of the Hand.",
"5. Campbell's Operative Orthopaedics, 15th Edition 2026 — Osteosarcoma; Giant Cell Tumour of Bone.",
"6. WHO Classification of Tumours of Soft Tissue and Bone, 4th Edition, 2013.",
];
refs.forEach((ref, i) => {
s.addText(ref, {
x: 0.8, y: 2.4 + i * 0.46, w: 8.4, h: 0.42, margin: 0,
fontSize: 8.5, color: C.lightGray, fontFace: "Calibri"
});
});
}
// ─────────────────────────────────────────────
// WRITE FILE
// ─────────────────────────────────────────────
const outPath = "/home/daytona/workspace/bone-tumour-ppt/Bone_Tumour_Imaging_Patterns.pptx";
pres.writeFile({ fileName: outPath })
.then(() => console.log(`\n✅ Saved: ${outPath}`))
.catch(err => { console.error("❌ Error:", err); process.exit(1); });