Face bone


| # | Bone | Count | Key Features |
|---|---|---|---|
| 1 | Mandible | 1 | Only movable skull bone; lower jaw; has condyle, coronoid process, and angle |
| 2 | Maxilla | 2 (paired) | Upper jaw; forms anterior hard palate, floor of orbit, lateral nasal wall; bears upper teeth |
| 3 | Zygomatic (Zygoma / Cheekbone) | 2 (paired) | Forms cheek prominence, lateral orbital wall and floor; articulates with temporal bone via zygomatic arch |
| 4 | Nasal | 2 (paired) | Bridge of the nose |
| 5 | Lacrimal | 2 (paired) | Smallest facial bones; medial orbital wall; contains lacrimal fossa for tear drainage |
| 6 | Palatine | 2 (paired) | Posterior hard palate; contributes to floor of orbit and lateral nasal wall |
| 7 | Inferior nasal concha | 2 (paired) | Scroll-shaped; project into nasal cavity as turbinates (increase surface area for air conditioning) |
| 8 | Vomer | 1 | Flat bone forming the lower/posterior nasal septum |
| Wall | Bone(s) |
|---|---|
| Roof | Frontal bone |
| Lateral wall + lateral floor | Zygomatic bone |
| Medial floor + anteromedial wall | Maxilla |
| Medial wall | Lacrimal + Ethmoid (most fragile - "blowout" fractures occur here) |
Tumours osteosarcoma seminar
mkdir -p /tmp/workspace/osteosarcoma-seminar && ls /tmp/workspace/osteosarcoma-seminar/
~/osteosarcoma-seminar/build_pptx.py
import json, subprocess, base64, sys
from io import BytesIO
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.oxml.ns import qn
from lxml import etree
# ── Colours ──────────────────────────────────────────────────────────────
DARK_BLUE = RGBColor(0x1A, 0x37, 0x6C) # deep navy
MID_BLUE = RGBColor(0x2E, 0x6D, 0xB4) # accent blue
LIGHT_BLUE = RGBColor(0xD6, 0xE8, 0xF7) # slide background tint
RED_ACCENT = RGBColor(0xC0, 0x39, 0x2B) # highlight
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
DARK_GREY = RGBColor(0x2C, 0x2C, 0x2C)
MID_GREY = RGBColor(0x55, 0x55, 0x55)
LIGHT_GREY = RGBColor(0xF2, 0xF4, 0xF7)
# ── Helper utilities ──────────────────────────────────────────────────────
def add_rect(slide, l, t, w, h, fill_rgb=None, line_rgb=None, line_width_pt=0):
shape = slide.shapes.add_shape(1, Inches(l), Inches(t), Inches(w), Inches(h))
shape.line.fill.background()
if fill_rgb:
shape.fill.solid()
shape.fill.fore_color.rgb = fill_rgb
else:
shape.fill.background()
if line_rgb and line_width_pt:
shape.line.color.rgb = line_rgb
shape.line.width = Pt(line_width_pt)
else:
shape.line.fill.background()
return shape
def add_tb(slide, l, t, w, h, text, size, bold=False, color=DARK_GREY,
align=PP_ALIGN.LEFT, wrap=True, italic=False, font="Calibri"):
tb = slide.shapes.add_textbox(Inches(l), Inches(t), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = wrap
tf.margin_left = 0; tf.margin_right = 0
tf.margin_top = 0; tf.margin_bottom = 0
p = tf.paragraphs[0]
p.alignment = align
run = p.add_run()
run.text = text
run.font.name = font
run.font.size = Pt(size)
run.font.bold = bold
run.font.italic = italic
run.font.color.rgb = color
return tf
def add_bullet_tf(slide, l, t, w, h, items, size=13, color=DARK_GREY,
bold_first=False, font="Calibri", line_space=1.15):
tb = slide.shapes.add_textbox(Inches(l), Inches(t), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = 0; tf.margin_right = 0
tf.margin_top = 0; tf.margin_bottom = 0
from pptx.oxml.ns import qn
from lxml import etree
for i, item in enumerate(items):
if i == 0:
p = tf.paragraphs[0]
else:
p = tf.add_paragraph()
# line spacing
pPr = p._pPr
if pPr is None:
pPr = p._p.get_or_add_pPr()
lnSpc = etree.SubElement(pPr, qn('a:lnSpc'))
spcPct = etree.SubElement(lnSpc, qn('a:spcPct'))
spcPct.set('val', str(int(line_space * 100000)))
spcBef = etree.SubElement(pPr, qn('a:spcBef'))
spcPts = etree.SubElement(spcBef, qn('a:spcPts'))
spcPts.set('val', '800')
run = p.add_run()
if isinstance(item, tuple):
bullet, text = item
else:
bullet, text = "• ", item
run.text = bullet + text
run.font.name = font
run.font.size = Pt(size)
run.font.color.rgb = color
run.font.bold = (i == 0 and bold_first)
return tf
def fetch_images(urls):
result = json.loads(subprocess.check_output(
["python", "/tmp/skills/shared/scripts/fetch_images.py"] + urls
))
return result
def add_image_from_b64(slide, b64_str, l, t, w, h=None):
raw = base64.b64decode(b64_str.split(',')[1] if ',' in b64_str else b64_str)
buf = BytesIO(raw)
if h:
slide.shapes.add_picture(buf, Inches(l), Inches(t), Inches(w), Inches(h))
else:
slide.shapes.add_picture(buf, Inches(l), Inches(t), Inches(w))
# ── Fetch all images ──────────────────────────────────────────────────────
IMAGE_URLS = [
"https://cdn.orris.care/cdss_images/393983627f910dbe2890e4171c6754c66b496a5b5bb49f34427b6303fced4c9a.png", # 0 X-ray Codman triangle
"https://cdn.orris.care/cdss_images/67d666f1c3d7c28aaef14dc5976c9abb955d31bb18ec7afbac8b996a2f8e8fc6.png", # 1 gross specimen
"https://cdn.orris.care/cdss_images/825ac63da1176854cfe0feab96138b8c8893240b7088f04166856fa60ded9702.png", # 2 histology
"https://cdn.orris.care/cdss_images/6f23f9305fb931f4bfc24c17ee2e15f3095932325f0d0c8655f7628ab82b2ad5.png", # 3 lytic/sclerotic X-rays
]
print("Fetching images...")
imgs = fetch_images(IMAGE_URLS)
print("Images fetched:", [bool(i["base64"]) for i in imgs])
# ── Presentation setup ────────────────────────────────────────────────────
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
blank = prs.slide_layouts[6]
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 1 – Title Slide
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, DARK_BLUE) # full bg
add_rect(s, 0, 5.5, 13.333, 2.0, MID_BLUE) # lower bar
add_rect(s, 0.55, 1.6, 0.07, 3.5, RED_ACCENT) # vertical accent line
add_tb(s, 0.9, 1.4, 11.5, 1.1, "OSTEOSARCOMA", 54, bold=True,
color=WHITE, align=PP_ALIGN.LEFT, font="Calibri")
add_tb(s, 0.9, 2.55, 11, 0.7, "Primary Malignant Bone Tumour — A Seminar", 22,
color=RGBColor(0xAD, 0xD4, 0xF0), align=PP_ALIGN.LEFT, italic=True)
add_tb(s, 0.9, 5.7, 9, 0.5, "Department of Orthopaedics / Pathology", 15,
color=WHITE, align=PP_ALIGN.LEFT)
add_tb(s, 0.9, 6.15, 9, 0.4, "Undergraduate MBBS Seminar | July 2026", 13,
color=RGBColor(0xAD, 0xD4, 0xF0), align=PP_ALIGN.LEFT)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 2 – Overview / Contents
# ═══════════════════════════════════════════════════════════════════════════
def slide_header(slide, title, subtitle=""):
add_rect(slide, 0, 0, 13.333, 1.15, DARK_BLUE)
add_rect(slide, 0, 1.15, 13.333, 0.06, MID_BLUE)
add_tb(slide, 0.45, 0.17, 12, 0.75, title, 28, bold=True,
color=WHITE, align=PP_ALIGN.LEFT)
if subtitle:
add_tb(slide, 0.45, 0.82, 12, 0.38, subtitle, 13,
color=RGBColor(0xAD, 0xD4, 0xF0), align=PP_ALIGN.LEFT, italic=True)
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Outline of Seminar")
topics = [
("01", "Definition & Introduction"),
("02", "Epidemiology & Risk Factors"),
("03", "Classification (WHO 2013)"),
("04", "Pathogenesis & Molecular Genetics"),
("05", "Clinical Features"),
("06", "Radiological Features"),
("07", "Pathology (Gross & Histology)"),
("08", "Diagnosis & Staging"),
("09", "Treatment"),
("10", "Prognosis & Complications"),
]
col1 = topics[:5]
col2 = topics[5:]
for i, (num, topic) in enumerate(col1):
y = 1.5 + i * 0.98
add_rect(s, 0.5, y, 0.55, 0.62, MID_BLUE)
add_tb(s, 0.5, y+0.08, 0.55, 0.5, num, 18, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_rect(s, 1.15, y, 5.5, 0.62, WHITE)
add_tb(s, 1.3, y+0.1, 5.2, 0.45, topic, 14, color=DARK_BLUE)
for i, (num, topic) in enumerate(col2):
y = 1.5 + i * 0.98
add_rect(s, 7.0, y, 0.55, 0.62, MID_BLUE)
add_tb(s, 7.0, y+0.08, 0.55, 0.5, num, 18, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_rect(s, 7.65, y, 5.3, 0.62, WHITE)
add_tb(s, 7.8, y+0.1, 5.1, 0.45, topic, 14, color=DARK_BLUE)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 3 – Definition & Introduction
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Definition & Introduction")
add_rect(s, 0.45, 1.45, 12.4, 1.5, WHITE)
add_tb(s, 0.65, 1.6, 12, 1.2,
"Osteosarcoma is a malignant tumour of bone in which the tumour cells form neoplastic "
"osteoid, bone, or both. It is the most common primary malignant bone tumour, excluding "
"haematopoietic tumours (e.g. multiple myeloma).",
14, color=DARK_GREY, wrap=True)
bullets = [
"Most common non-haematological primary bone malignancy",
"Tumour cells directly produce osteoid / bone matrix — the diagnostic hallmark",
"High-grade intramedullary lesion in 75% of all cases (conventional type)",
"All osteosarcomas are assumed to have occult micrometastases at time of diagnosis",
"5-year survival ~70% (no metastasis) with modern chemotherapy + surgery",
]
add_bullet_tf(s, 0.65, 3.15, 12, 3.8, bullets, size=13.5, color=DARK_GREY)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 4 – Epidemiology
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Epidemiology & Risk Factors")
# Left panel - Epidemiology
add_rect(s, 0.45, 1.4, 5.9, 5.6, WHITE)
add_tb(s, 0.65, 1.55, 5.6, 0.5, "Epidemiology", 16, bold=True, color=DARK_BLUE)
epi_bullets = [
"Incidence: ~4 per million population/year",
"Bimodal age distribution:",
" Peak 1 — Adolescents 10–20 yrs (75% of cases)",
" Peak 2 — Older adults (secondary OSA)",
"Male > Female (ratio 1.35–1.6 : 1)",
"Peak coincides with adolescent growth spurt",
"Almost 50%–75% occur near the knee",
" (distal femur or proximal tibia)",
]
add_bullet_tf(s, 0.65, 2.1, 5.6, 4.7, epi_bullets, size=12.5, color=DARK_GREY)
# Right panel - Risk factors
add_rect(s, 6.9, 1.4, 6.0, 5.6, WHITE)
add_tb(s, 7.1, 1.55, 5.7, 0.5, "Risk Factors / Associations", 16, bold=True, color=DARK_BLUE)
rf_bullets = [
("⚑ ", "Paget disease of bone"),
("⚑ ", "Previous radiation therapy"),
("⚑ ", "Bone infarcts"),
("⚑ ", "Li-Fraumeni syndrome (TP53 germline)"),
("⚑ ", "Familial retinoblastoma (RB1 germline)"),
("⚑ ", "Rothmund-Thomson syndrome"),
("⚑ ", "Fibrous dysplasia"),
("⚑ ", "Bone infarction / osteonecrosis"),
("⚑ ", "Prior low-grade sarcoma dedifferentiation"),
]
add_bullet_tf(s, 7.1, 2.1, 5.7, 4.7, rf_bullets, size=12.5, color=DARK_GREY)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 5 – WHO Classification
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Classification of Osteosarcoma", "WHO 2013 — Seven Categories")
types = [
("1", "Conventional Osteosarcoma", "75% of all cases. High-grade intramedullary. Osteoblastic, chondroblastic or fibroblastic subtypes.", MID_BLUE),
("2", "Telangiectatic Osteosarcoma", "Blood-filled cavities. May mimic ABC on X-ray. High-grade.", DARK_BLUE),
("3", "Low-Grade Central OSA", "Resembles fibrous dysplasia. Well-differentiated. Better prognosis.", RGBColor(0x27, 0xAE, 0x60)),
("4", "Small Cell Osteosarcoma", "Resembles Ewing sarcoma. Small round blue cells + osteoid.", RED_ACCENT),
("5", "Parosteal Osteosarcoma", "Surface lesion, posterior distal femur. Low-grade. Best prognosis.", RGBColor(0x84, 0x44, 0xAD)),
("6", "Periosteal Osteosarcoma", "Surface, intermediate grade. Chondroblastic variant.", RGBColor(0x16, 0xA0, 0x85)),
("7", "High-Grade Surface OSA", "Rare. Surface location but high-grade histology.", RGBColor(0xD3, 0x5A, 0x00)),
]
for i, (num, name, desc, col) in enumerate(types):
row = i % 4
col_idx = i // 4
x = 0.45 + col_idx * 6.55
y = 1.5 + row * 1.45
add_rect(s, x, y, 6.1, 1.3, WHITE)
add_rect(s, x, y, 0.45, 1.3, col)
add_tb(s, x+0.02, y+0.3, 0.45, 0.7, num, 18, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_tb(s, x+0.6, y+0.07, 5.3, 0.45, name, 13, bold=True, color=col)
add_tb(s, x+0.6, y+0.52, 5.3, 0.72, desc, 11, color=DARK_GREY, wrap=True)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 6 – Pathogenesis & Molecular Genetics
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Pathogenesis & Molecular Genetics")
add_tb(s, 0.5, 1.35, 12.5, 0.4,
"Peak incidence during adolescent growth spurt — rapidly proliferating metaphyseal cells prone to mutations",
13, italic=True, color=MID_GREY)
genes = [
("RB1", "Retinoblastoma gene", "Mutated in up to 70% of sporadic OSA\nGermline RB1 mutations increase risk 1000-fold", MID_BLUE),
("TP53", "Tumour suppressor", "Mutated in Li-Fraumeni syndrome\nCommon in sporadic tumours", RED_ACCENT),
("MDM2/CDK4", "Oncogenes", "Overexpressed in low-grade OSA\nInhibit p53 and RB function respectively", RGBColor(0x27, 0xAE, 0x60)),
("CDKN2A", "INK4a locus", "Encodes p16 and p14 tumour suppressors\nInactivated in many OSA", RGBColor(0xD3, 0x5A, 0x00)),
("MYC", "Proto-oncogene", "Amplified in up to 50% of cases\nAssociated with particularly poor prognosis", RGBColor(0x84, 0x44, 0xAD)),
]
for i, (gene, role, detail, col) in enumerate(genes):
x = 0.45 + i * 2.55
add_rect(s, x, 1.95, 2.3, 4.9, WHITE)
add_rect(s, x, 1.95, 2.3, 0.65, col)
add_tb(s, x+0.1, 2.02, 2.1, 0.5, gene, 16, bold=True, color=WHITE)
add_tb(s, x+0.1, 2.72, 2.1, 0.45, role, 11, bold=True, color=col)
add_tb(s, x+0.1, 3.2, 2.1, 3.5, detail, 11, color=DARK_GREY, wrap=True)
add_tb(s, 0.5, 7.0, 12.5, 0.38,
"Note: Complex karyotypes with numerous chromosomal aberrations characterise osteosarcoma",
12, italic=True, color=MID_GREY)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 7 – Clinical Features
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Clinical Features")
# Symptoms
add_rect(s, 0.45, 1.4, 5.9, 2.75, WHITE)
add_tb(s, 0.65, 1.52, 5.6, 0.42, "Symptoms", 15, bold=True, color=DARK_BLUE)
syms = [
"Pain — most common presenting complaint",
"Progressively enlarging painful mass",
"Night pain (characteristic)",
"Pathological fracture (first presentation in some)",
"Neurological symptoms (70% in spinal OSA)",
]
add_bullet_tf(s, 0.65, 2.0, 5.6, 2.0, syms, size=12.5)
# Sites
add_rect(s, 0.45, 4.3, 5.9, 2.75, WHITE)
add_tb(s, 0.65, 4.42, 5.6, 0.42, "Common Sites", 15, bold=True, color=DARK_BLUE)
sites = [
"Distal femur (most common, ~30%)",
"Proximal tibia (~25%)",
"Proximal humerus (~15%)",
"50%–75% occur near the knee",
"Rare: ilium, ribs, scapula, jaw, spine",
]
add_bullet_tf(s, 0.65, 4.85, 5.6, 2.0, sites, size=12.5)
# Signs
add_rect(s, 6.9, 1.4, 6.0, 2.75, WHITE)
add_tb(s, 7.1, 1.52, 5.7, 0.42, "Signs on Examination", 15, bold=True, color=DARK_BLUE)
signs = [
"Hard, tender, fixed mass over metaphysis",
"Overlying skin warm and erythematous",
"Dilated superficial veins",
"Limited adjacent joint movement",
"Muscle wasting distal to tumour",
"Lymphadenopathy (uncommon)",
]
add_bullet_tf(s, 7.1, 1.95, 5.7, 2.0, signs, size=12.5)
# Red flags
add_rect(s, 6.9, 4.3, 6.0, 2.75, WHITE)
add_rect(s, 6.9, 4.3, 6.0, 0.5, RED_ACCENT)
add_tb(s, 7.0, 4.37, 5.7, 0.42, "🚩 Red Flag Features", 15, bold=True, color=WHITE)
flags = [
"Age 10–20 with bone pain + swelling",
"Pain worse at rest / night",
"Rapid progression",
"Raised ALP and LDH (markers of activity)",
]
add_bullet_tf(s, 7.1, 4.9, 5.7, 2.0, flags, size=12.5, color=RED_ACCENT)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 8 – Radiological Features
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Radiological Features")
# X-ray image (Codman triangle)
if imgs[0]["base64"]:
add_image_from_b64(s, imgs[0]["base64"], 0.45, 1.35, 4.0, 5.8)
add_tb(s, 0.45, 7.1, 4.1, 0.35,
"X-ray: Distal femur OSA with Codman triangle (arrow)", 10, italic=True, color=MID_GREY)
# Radiology bullet points
add_rect(s, 4.9, 1.35, 8.0, 5.8, WHITE)
add_tb(s, 5.1, 1.5, 7.7, 0.45, "Plain Radiograph Findings", 16, bold=True, color=DARK_BLUE)
rad_bullets = [
"Metaphyseal location (long bones)",
"Mixed lytic + sclerotic pattern (most common)",
"Entirely lytic in 13% of cases",
"Entirely sclerotic (ivory-like) in some",
"Cortical destruction with eccentric soft-tissue mass",
"Periosteal reactions (pathognomonic patterns):",
" • Codman triangle — reactive subperiosteal bone",
" • Sunburst / spiculated pattern",
" • Onion-skin (lamellated) pattern",
" • Any combination may be present",
"",
"MRI (mandatory for staging):",
" • Defines tumour extent in bone & soft tissue",
" • Identifies skip metastases",
" • Neurovascular involvement",
" • Joint involvement",
]
add_bullet_tf(s, 5.1, 2.05, 7.7, 5.0, rad_bullets, size=12)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 9 – Gross & Histopathology
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Pathology — Gross & Histology")
# Gross image
if imgs[1]["base64"]:
add_image_from_b64(s, imgs[1]["base64"], 0.45, 1.35, 3.8, 4.5)
add_tb(s, 0.45, 5.9, 3.9, 0.5,
"Gross: Distal femur OSA — cortical disruption,\nhaemorrhage, confined to metaphysis", 10, italic=True, color=MID_GREY, wrap=True)
# Histology image
if imgs[2]["base64"]:
add_image_from_b64(s, imgs[2]["base64"], 4.55, 1.35, 3.8, 4.5)
add_tb(s, 4.55, 5.9, 3.9, 0.5,
"Histology: Lancelike osteoid by pleomorphic cells;\nabnormal mitotic figure (arrow)", 10, italic=True, color=MID_GREY, wrap=True)
# Text panel
add_rect(s, 8.75, 1.35, 4.15, 5.75, WHITE)
add_tb(s, 8.95, 1.5, 3.9, 0.42, "Key Pathological Features", 14, bold=True, color=DARK_BLUE)
path_bullets = [
"Bulky, gritty, tan-white tumour",
"Areas of haemorrhage and necrosis",
"Intramedullary spread — replaces marrow",
"Cortical destruction into soft tissue",
"Rarely enters adjacent joint",
"",
"Histology:",
"• Cell pleomorphism + hyperchromatic nuclei",
"• Bizarre tumour giant cells",
"• Abundant mitoses (incl. abnormal bipolar)",
"• Fine lacelike or sheet-like osteoid — ESSENTIAL for Dx",
"• Intravascular invasion common",
]
add_bullet_tf(s, 8.95, 2.0, 3.9, 5.0, path_bullets, size=11.5, color=DARK_GREY)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 10 – Diagnosis & Staging
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Diagnosis & Staging")
# Left
add_rect(s, 0.45, 1.4, 5.9, 5.65, WHITE)
add_tb(s, 0.65, 1.55, 5.6, 0.45, "Investigations", 15, bold=True, color=DARK_BLUE)
inv = [
("Lab:", "ALP ↑, LDH ↑ (activity markers); FBC; renal/liver function"),
("X-ray:", "First-line; classic periosteal patterns"),
("MRI:", "MANDATORY for local staging — whole bone"),
("CT chest:", "Screen for pulmonary metastases (commonest site)"),
("Bone scan:", "Identify skip metastases, bone metastases"),
("PET-CT:", "More sensitive than bone scan in paediatric sarcoma"),
("Biopsy:", "DEFINITIVE diagnosis — open or core needle\n(in specialist centre, along tumour axis)"),
]
y = 2.05
for label, text in inv:
tb = s.shapes.add_textbox(Inches(0.65), Inches(y), Inches(5.6), Inches(0.7))
tf = tb.text_frame; tf.word_wrap = True
tf.margin_left=0; tf.margin_right=0; tf.margin_top=0; tf.margin_bottom=0
p = tf.paragraphs[0]
r1 = p.add_run(); r1.text = label + " "; r1.font.bold = True
r1.font.size = Pt(12); r1.font.color.rgb = DARK_BLUE; r1.font.name = "Calibri"
r2 = p.add_run(); r2.text = text
r2.font.size = Pt(12); r2.font.color.rgb = DARK_GREY; r2.font.name = "Calibri"
y += 0.72
# Right
add_rect(s, 6.9, 1.4, 6.0, 5.65, WHITE)
add_tb(s, 7.1, 1.55, 5.7, 0.45, "Staging — Enneking / MSTS System", 15, bold=True, color=DARK_BLUE)
staging = [
("Stage IA:", "Low-grade, intracompartmental (T1)"),
("Stage IB:", "Low-grade, extracompartmental (T2)"),
("Stage IIA:", "High-grade, intracompartmental (T1)"),
("Stage IIB:", "High-grade, extracompartmental (T2) — MOST OSA"),
("Stage III:", "Any grade with regional or distant metastasis"),
]
y2 = 2.05
for label, text in staging:
tb = s.shapes.add_textbox(Inches(7.1), Inches(y2), Inches(5.7), Inches(0.6))
tf = tb.text_frame; tf.word_wrap = True
tf.margin_left=0; tf.margin_right=0; tf.margin_top=0; tf.margin_bottom=0
p = tf.paragraphs[0]
r1 = p.add_run(); r1.text = label + " "
r1.font.bold = True; r1.font.size = Pt(12); r1.font.color.rgb = MID_BLUE; r1.font.name = "Calibri"
r2 = p.add_run(); r2.text = text
r2.font.size = Pt(12); r2.font.color.rgb = DARK_GREY; r2.font.name = "Calibri"
y2 += 0.68
add_rect(s, 6.9, 5.4, 6.0, 1.65, LIGHT_BLUE)
add_tb(s, 7.1, 5.5, 5.7, 1.4,
"Biopsy is the gold standard for diagnosis.\n"
"Biopsy tract must be excised en bloc with the tumour.\n"
"Always perform in a specialist sarcoma centre.",
12, color=DARK_BLUE, wrap=True, italic=True)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 11 – Treatment
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Treatment")
# Timeline bar
steps = [
("1\nNeoadjuvant\nChemo", MID_BLUE, "MAP protocol\n(Methotrexate,\nAdriaymcin, Cisplatin)\n8–12 weeks"),
("2\nSurgery", DARK_BLUE, "Limb-salvage surgery\n(preferred) or\namputation if\nneurovascular involved"),
("3\nHistological\nResponse", RGBColor(0x27, 0xAE, 0x60), "Assess tumour necrosis\n≥90% necrosis = good\nresponse (favourable)"),
("4\nAdjuvant\nChemo", MID_BLUE, "Continue MAP\n(± ifosfamide if\npoor responder)\n~12–18 weeks"),
]
for i, (step, col, detail) in enumerate(steps):
x = 0.45 + i * 3.2
add_rect(s, x, 1.4, 2.9, 1.0, col)
add_tb(s, x, 1.4, 2.9, 1.0, step, 13, bold=True, color=WHITE, align=PP_ALIGN.CENTER, wrap=True)
add_rect(s, x, 2.5, 2.9, 2.2, WHITE)
add_tb(s, x+0.15, 2.6, 2.6, 2.0, detail, 12, color=DARK_GREY, wrap=True)
if i < 3:
add_tb(s, x+2.95, 1.75, 0.25, 0.5, "→", 22, bold=True, color=DARK_BLUE, align=PP_ALIGN.CENTER)
# Surgery details
add_rect(s, 0.45, 4.9, 12.45, 2.3, WHITE)
add_tb(s, 0.65, 5.05, 12, 0.4, "Surgical Principles", 15, bold=True, color=DARK_BLUE)
surg = [
"Limb-salvage surgery (LSS) is now possible in ~85–90% of cases due to effective neoadjuvant chemotherapy",
"Wide margin excision (en bloc) with reconstruction: endoprosthesis, allograft, or rotationplasty",
"Amputation: reserved for unresectable cases or where LSS compromises oncological outcome",
"Radiation therapy: limited role (OSA is relatively radio-resistant); used for unresectable spinal or pelvic lesions",
]
add_bullet_tf(s, 0.65, 5.5, 12, 1.6, surg, size=12)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 12 – Prognosis & Complications
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Prognosis & Complications")
# Prognosis boxes
prog_data = [
("~70%", "5-year survival\n(no metastasis)", MID_BLUE),
("<30%", "5-year survival\n(with metastasis)", RED_ACCENT),
("≥90%", "Tumour necrosis\n= good response", RGBColor(0x27, 0xAE, 0x60)),
("~20%", "5-year survival\nspinal OSA", RGBColor(0xD3, 0x5A, 0x00)),
]
for i, (val, label, col) in enumerate(prog_data):
x = 0.45 + i * 3.22
add_rect(s, x, 1.4, 2.9, 1.5, col)
add_tb(s, x, 1.55, 2.9, 0.85, val, 38, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_tb(s, x, 2.3, 2.9, 0.6, label, 12, color=WHITE, align=PP_ALIGN.CENTER, wrap=True)
# Prognostic factors
add_rect(s, 0.45, 3.1, 5.9, 4.05, WHITE)
add_tb(s, 0.65, 3.25, 5.6, 0.42, "Favourable Prognostic Factors", 14, bold=True, color=RGBColor(0x27, 0xAE, 0x60))
fav = [
"Age < 40 years",
"Distal extremity location",
"No metastasis at diagnosis",
"≥90% histological necrosis post-chemo",
"Complete surgical resection (wide margins)",
"Low ALP at diagnosis",
]
add_bullet_tf(s, 0.65, 3.75, 5.6, 3.2, fav, size=12.5, color=DARK_GREY)
add_rect(s, 6.9, 3.1, 6.0, 4.05, WHITE)
add_tb(s, 7.1, 3.25, 5.7, 0.42, "Complications & Metastases", 14, bold=True, color=RED_ACCENT)
comp = [
"Haematogenous spread — lungs (most common)",
"Bone metastases, brain, other sites",
"Skip metastases (same bone, across joint)",
"Pathological fracture",
"Local recurrence after surgery",
"Chemotherapy toxicity (cardiotoxicity, nephrotoxicity)",
"Prosthesis failure / aseptic loosening",
"Poor prognosis if clinically evident metastasis at Dx",
]
add_bullet_tf(s, 7.1, 3.75, 5.7, 3.2, comp, size=12.5, color=DARK_GREY)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 13 – Differential Diagnosis
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, LIGHT_GREY)
slide_header(s, "Differential Diagnosis")
diffs = [
("Ewing Sarcoma", "Age 10–20; diaphysis; 'onion skin' periosteal reaction;\nsmall round blue cells on histology; no osteoid", MID_BLUE),
("Chondrosarcoma", "Adults >40; lytic with rings & arcs calcification;\ncartilage matrix; low to intermediate grade", DARK_BLUE),
("Giant Cell Tumour", "Age 20–40; epiphysis; soap-bubble lytic lesion;\nno matrix; osteoclast-like giant cells", RGBColor(0x27, 0xAE, 0x60)),
("Osteoid Osteoma", "Age 10–30; diaphysis; nocturnal pain relieved by aspirin;\nnidus <2 cm; reactive sclerosis; benign", RGBColor(0xD3, 0x5A, 0x00)),
("Metastatic Bone Disease", "Adults >40; multiple lesions; known primary elsewhere;\nlytic (most) or sclerotic (prostate, breast)", RED_ACCENT),
("Aneurysmal Bone Cyst", "Any age; expansile lytic; fluid-fluid levels on MRI;\ncan mimic telangiectatic OSA; benign", RGBColor(0x84, 0x44, 0xAD)),
]
for i, (name, desc, col) in enumerate(diffs):
row = i % 3
ci = i // 3
x = 0.45 + ci * 6.55
y = 1.4 + row * 1.9
add_rect(s, x, y, 6.1, 1.75, WHITE)
add_rect(s, x, y, 0.1, 1.75, col)
add_tb(s, x+0.25, y+0.12, 5.7, 0.45, name, 14, bold=True, color=col)
add_tb(s, x+0.25, y+0.57, 5.7, 1.1, desc, 12, color=DARK_GREY, wrap=True)
# ═══════════════════════════════════════════════════════════════════════════
# SLIDE 14 – Summary
# ═══════════════════════════════════════════════════════════════════════════
s = prs.slides.add_slide(blank)
add_rect(s, 0, 0, 13.333, 7.5, DARK_BLUE)
add_rect(s, 0, 5.5, 13.333, 2.0, MID_BLUE)
add_rect(s, 0.55, 1.6, 0.07, 3.5, RED_ACCENT)
add_tb(s, 0.9, 1.35, 11.5, 0.8, "Key Take-Home Points", 30, bold=True,
color=WHITE, align=PP_ALIGN.LEFT)
summary = [
"Most common primary malignant bone tumour (excl. haematological)",
"Bimodal age: adolescent peak (10–20 yrs) + older adults (secondary OSA)",
"Metaphysis of long bones around the knee in 50–75% of cases",
"Diagnostic hallmark: malignant cells producing osteoid / bone matrix",
"Classic X-ray: mixed lytic-sclerotic, Codman triangle, sunburst periosteal reaction",
"Treatment: Neoadjuvant chemo → Limb-salvage surgery → Adjuvant chemo (MAP)",
"5-year survival ~70% without metastasis; <30% with metastasis",
"Lungs are the most common site of distant metastasis",
]
for i, point in enumerate(summary):
add_tb(s, 1.05, 2.35 + i * 0.59, 11.5, 0.55,
f" ✓ {point}", 13, color=WHITE if i % 2 == 0 else RGBColor(0xAD, 0xD4, 0xF0),
wrap=True)
add_tb(s, 0.9, 5.7, 9, 0.5, "Sources: Robbins & Kumar Basic Pathology | Grainger & Allison Diagnostic Radiology | Campbell's Operative Orthopaedics 2026", 11,
color=WHITE, align=PP_ALIGN.LEFT, italic=True)
# ── Save ──────────────────────────────────────────────────────────────────
out = "/tmp/workspace/osteosarcoma-seminar/Osteosarcoma_Seminar_MBBS.pptx"
prs.save(out)
print(f"Saved: {out}")
cd /tmp/workspace/osteosarcoma-seminar && python build_pptx.py 2>&1
find /tmp/skills -name "fetch_images.py" 2>/dev/null; ls /tmp/skills/
~/osteosarcoma-seminar/build_pptx.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/osteosarcoma-seminar/build_pptx.py'
~/osteosarcoma-seminar/build_pptx.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/osteosarcoma-seminar/build_pptx.py'
cd /tmp/workspace/osteosarcoma-seminar && python build_pptx.py 2>&1
ls -lh /tmp/workspace/osteosarcoma-seminar/Osteosarcoma_Seminar_MBBS.pptx
Osteosarcoma Seminar MBBS
Presentation · PPTX
| Slide | Content |
|---|---|
| 1 | Title slide — navy/blue professional design |
| 2 | Seminar outline — 10 topics with numbered boxes |
| 3 | Definition & Introduction — what is osteosarcoma, key facts |
| 4 | Epidemiology & Risk Factors — incidence, bimodal age, associations (Paget, radiation, Li-Fraumeni, RB) |
| 5 | WHO 2013 Classification — all 7 types with descriptions (conventional to high-grade surface) |
| 6 | Pathogenesis & Molecular Genetics — RB1, TP53, MDM2, CDK4, CDKN2A, MYC in colour-coded gene cards |
| 7 | Clinical Features — symptoms, signs, common sites, red flags |
| 8 | Radiological Features — X-ray showing Codman triangle (real textbook image), periosteal patterns, MRI role |
| 9 | Gross & Histopathology — real gross specimen photo + H&E histology image with key features |
| 10 | Diagnosis & Staging — investigations (ALP, MRI, CT chest, biopsy) + Enneking staging |
| 11 | Treatment — MAP chemotherapy → limb salvage surgery → adjuvant chemo timeline |
| 12 | Prognosis & Complications — survival statistics, prognostic factors, metastasis |
| 13 | Differential Diagnosis — Ewing sarcoma, chondrosarcoma, GCT, OO, metastases, ABC |
| 14 | Summary — 8 take-home points |
Face muscle


| Muscle | CN VII Branch | Action | Clinical Effect if Lost |
|---|---|---|---|
| Frontalis (part of epicranius) | Temporal | Raises eyebrows; horizontal forehead lines | Cannot raise brow; forehead lines flatten |
| Corrugator supercilii | Temporal | Draws brows medially & downward ("scowl") | Difficulty frowning/scowling |
| Procerus | Zygomatic | Shortens nose; "bunny lines" with nasalis | Loss of bunny lines on nose bridge |
| Muscle | CN VII Branch | Action | Clinical Effect if Lost |
|---|---|---|---|
| Orbicularis oculi (orbital part) | Temporal | Tight voluntary eye closure | Inability to close eye tightly - risk of corneal damage |
| Orbicularis oculi (palpebral part) | Temporal/Zygomatic | Gentle closure, blinking, tear drainage | Lagophthalmos, ectropion |
| Auricularis anterior & superior | Temporal | Draws temporal skin back | Minimal functional loss |
| Auricularis posterior | Posterior auricular | Draws temporal skin back | Minimal functional loss |
| Muscle | CN VII Branch | Action |
|---|---|---|
| Nasalis (transverse part) | Zygomatic | Compresses nostrils |
| Nasalis (alar part) | Zygomatic | Flares nostrils |
| Depressor septi nasi | Buccal | Pulls columella toward lip; depresses nasal tip |
| Muscle | CN VII Branch | Action | Clinical Effect if Lost |
|---|---|---|---|
| Orbicularis oris | Buccal & Marginal mandibular | Closes & purses lips; sphincter of mouth | Cannot close lips; difficulty speaking, eating |
| Zygomaticus major | Zygomatic & Buccal | Elevates & retracts mouth corners (smile) | Difficulty smiling |
| Zygomaticus minor | Buccal | Elevates upper lip | Altered smile |
| Levator labii superioris | Buccal | Elevates upper lip | Loss of nasolabial fold |
| Levator labii superioris alaeque nasi | Buccal | Elevates lip + flares nostril | - |
| Levator anguli oris | Zygomatic & Buccal | Elevates angle of mouth | Drooping of mouth angle |
| Buccinator | Buccal | Compresses cheek against teeth; prevents food pocketing; aids whistling | Food collects in cheek; cannot whistle |
| Risorius | Buccal / Marginal mandibular | Retracts angle of mouth (grin) | Asymmetric smile |
| Depressor anguli oris | Marginal mandibular | Depresses angle of mouth | Lip droops upward |
| Depressor labii inferioris | Marginal mandibular | Depresses & everts lower lip | Lower lip held too high |
| Mentalis | Marginal mandibular | Elevates & protrudes lower lip; wrinkles chin skin | "Witches chin" deformity |
| Platysma | Cervical branch | Depresses mandible; tightens neck skin | Loss of neck skin tension |
| Muscle | Action | Notes |
|---|---|---|
| Masseter | Elevation + protrusion of mandible | Most powerful jaw closer; palpable on biting |
| Temporalis | Elevation + retraction of mandible | Fan-shaped; fills temporal fossa |
| Medial pterygoid | Elevation of mandible | Works with masseter to form a "sling" |
| Lateral pterygoid (superior head) | Elevation + protrusion | Only masticatory muscle active during closing |
| Lateral pterygoid (inferior head) | Depression + lateral displacement of mandible | Opens jaw; protrudes chin |
| Digastric (anterior belly) | Depression + retraction of mandible | Also a suprahyoid muscle |
| Mylohyoid | Depression of mandible | Forms floor of mouth |
| Geniohyoid | Depression of mandible | Innervated by C1 via CN XII (not CN V3) |
| Point | Detail |
|---|---|
| SMAS layer | Connects facial muscles into a coordinated unit; key landmark in facelifts and parotid surgery |
| Bell's palsy | LMN CN VII palsy - all ipsilateral muscles paralysed (forehead + lower face); brow cannot be raised |
| UMN facial palsy (stroke) | Spares the upper face (forehead) because frontalis has bilateral cortical representation |
| Wrinkle lines | Perpendicular to muscle fiber direction - useful for elliptical incision planning |
| Buccinator | Unique - it is a muscle of facial expression but also functions in mastication (keeps food between teeth) |
| Parotid gland | Lies superficial to masseter; facial nerve branches fan out through it to reach expression muscles |