Right approach and PHYSIOTHERAPY protocol after TKR
"total knee replacement" AND "physiotherapy" AND "rehabilitation"
PMID: 40635148
physiotherapy rehabilitation protocol after total knee replacement TKR phases exercises 2024
https://www.sportssurgeryclinic.com/wp-content/uploads/2021/…
https://www.royalberkshire.nhs.uk/media/ww5bknsi/advice-and-…
| Exercise | Technique |
|---|---|
| Static Quads (Quad sets) | Lie flat, push back of knee into bed, pull toes up, hold 5-10 sec |
| Straight Leg Raise (SLR) | Tighten quads, lift leg ~2 inches, hold 5-10 sec |
| Inner Range Quads | Towel rolled under knee, straighten knee lifting heel, hold 5-10 sec |
| Full Range Quads | Sitting on chair/bed, extend knee fully, hold 10 sec |
| Static Gluteals | Tighten buttock muscles, hold 5-10 sec |
| Knee Flexion in Sitting | Bend knee as far as possible, hold 8-10 sec |
| Ankle Pumps | Dorsiflexion/plantarflexion - continuous, every waking hour (DVT prevention) |
| Foot Circles | Circular ankle movements |
| Heel Slides | Lying flat, slide heel toward buttock |
| Exercise | Notes |
|---|---|
| Short Arc Quads | Towel under knee, extend from ~30° to full extension |
| Hamstring Isometrics | Progress to concentric/eccentric |
| Heel Raises | Bilateral first, progress to single leg |
| Sit to Stand | From progressively lower chairs |
| Mini Squats | To 30-45°, ensure correct alignment |
| Step-ups | Begin with low step (10 cm), progress height |
| Step-downs (eccentric) | Control descent |
| Aggressive Flexion ROM | Passive, active-assisted, active - sitting and supine |
| Extension ROM | Prolonged low-load stretching (prone hang or heel on roll) |
| Exercise | Notes |
|---|---|
| Leg Press | Low range initially, increase load progressively |
| Terminal Knee Extension (TKE) | Theraband resistance |
| Stationary Cycling | Excellent for ROM and endurance; begin when flexion ≥90° |
| Step Machine / Stair climbing | Reciprocal pattern |
| Wall Slides / Partial Squats | 0-60° initially |
| Lateral Band Walks | Hip abductor/external rotator strengthening |
| Single-Leg Balance | Unaided, progress to unstable surface |
| Hip Strengthening | Abduction, extension, external rotation |
| Treadmill Walking | Speed progression |
| Timeframe | Flexion Target | Extension Target |
|---|---|---|
| Day 1-2 | 60-70° | 0° (full) |
| 2 weeks | 90°+ | 0° |
| 6 weeks | 110°+ | 0° |
| 3 months | 120-130° | 0° |
| Final (1 year) | 120-135° | 0° (no deficit) |
| Modality | Evidence | Recommendation |
|---|---|---|
| Continuous Passive Motion (CPM) | Not proven to improve long-term ROM | Not routinely recommended; may be used early for ROM in selected cases |
| NMES/EMS | Good evidence for quadriceps strengthening | Recommended especially if SLR lag persists |
| Cryotherapy/Ice | Reduces swelling and pain | Yes, routinely |
| Manual Lymphatic Drainage | 2024 meta-analysis supports use | Recommended for swelling management |
| Telerehabilitation | 2024 SR (PMID 38574249) shows effectiveness comparable to in-person for elderly | Viable for maintenance phase or remote patients |
| Aquatic Therapy | Good evidence, especially for obese patients | After wound healing |
| Multidisciplinary Approach | 2025 SR (PMID 40770481) shows reduces kinesiophobia vs. routine PT alone | Recommended to address fear-avoidance |
As a physio day 1 what I do
| What to Do | What NOT to Do |
|---|---|
| Ankle pumps every waking hour | Do NOT put a pillow under the knee |
| Keep leg elevated when in bed | Do NOT sit with knee hanging in flexion for long periods |
| Ice 3-4x per day | Do NOT force flexion into severe pain |
| Try to achieve full extension actively | Do NOT miss exercises |
| Report any calf pain, chest pain, sudden breathlessness | Do NOT bear weight without walking aid |
| Parameter | Typical Day 1 Finding |
|---|---|
| Flexion ROM | 60-80° |
| Extension | May have 5-10° lag initially - aim to correct |
| SLR | Often with lag or not possible - acceptable |
| Walking distance | Few metres to end of ward |
| Pain | Moderate - 4-6/10 even with analgesia |
Generate a patient education handout for post-TKR home exercises
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && echo "workspace ready"
mkdir -p /tmp/workspace/tkr-handout && cat > /tmp/workspace/tkr-handout/create_handout.py << 'PYEOF' from docx import Document from docx.shared import Pt, Inches, RGBColor, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL from docx.oxml.ns import qn from docx.oxml import OxmlElement import copy doc = Document() # ── Page margins ────────────────────────────────────────────────────────────── section = doc.sections[0] section.page_width = Inches(8.27) # A4 section.page_height = Inches(11.69) section.top_margin = Cm(1.8) section.bottom_margin = Cm(1.8) section.left_margin = Cm(2.0) section.right_margin = Cm(2.0) # ── Colour palette ─────────────────────────────────────────────────────────── BLUE_DARK = RGBColor(0x00, 0x4E, 0x9A) # header / banner BLUE_MID = RGBColor(0x00, 0x7B, 0xC2) # section headings BLUE_LIGHT = RGBColor(0xD6, 0xEB, 0xF7) # table header fill ORANGE = RGBColor(0xE8, 0x6A, 0x1A) # warning / red-flag accent GREEN = RGBColor(0x2E, 0x7D, 0x32) # "do" items WHITE = RGBColor(0xFF, 0xFF, 0xFF) GREY_LIGHT = RGBColor(0xF4, 0xF6, 0xF8) # ── Helper: set cell shading ───────────────────────────────────────────────── def shade_cell(cell, hex_color): tc = cell._tc tcPr = tc.get_or_add_tcPr() shd = OxmlElement('w:shd') shd.set(qn('w:val'), 'clear') shd.set(qn('w:color'), 'auto') shd.set(qn('w:fill'), hex_color) tcPr.append(shd) def set_cell_border(cell, **kwargs): tc = cell._tc tcPr = tc.get_or_add_tcPr() tcBorders = OxmlElement('w:tcBorders') for edge in ('top','left','bottom','right'): tag = OxmlElement(f'w:{edge}') tag.set(qn('w:val'), kwargs.get('val', 'single')) tag.set(qn('w:sz'), kwargs.get('sz', '4')) tag.set(qn('w:color'), kwargs.get('color', 'auto')) tcBorders.append(tag) tcPr.append(tcBorders) def para_space(doc, before=0, after=0): p = doc.add_paragraph() pf = p.paragraph_format pf.space_before = Pt(before) pf.space_after = Pt(after) return p def add_section_heading(doc, text, color=BLUE_MID): p = doc.add_paragraph() pf = p.paragraph_format pf.space_before = Pt(10) pf.space_after = Pt(4) run = p.add_run(text.upper()) run.bold = True run.font.size = Pt(12) run.font.color.rgb = color # bottom border under heading pPr = p._p.get_or_add_pPr() pBdr = OxmlElement('w:pBdr') bottom = OxmlElement('w:bottom') bottom.set(qn('w:val'), 'single') bottom.set(qn('w:sz'), '6') bottom.set(qn('w:space'), '2') bottom.set(qn('w:color'), '%02X%02X%02X' % (color.red, color.green, color.blue)) pBdr.append(bottom) pPr.append(pBdr) return p def add_exercise_row(table, num, name, position, instructions, reps, freq): row = table.add_row() cells = row.cells # Number p = cells[0].paragraphs[0] run = p.add_run(str(num)) run.bold = True run.font.size = Pt(10) run.font.color.rgb = WHITE p.alignment = WD_ALIGN_PARAGRAPH.CENTER shade_cell(cells[0], '%02X%02X%02X' % (BLUE_MID.red, BLUE_MID.green, BLUE_MID.blue)) cells[0].vertical_alignment = WD_ALIGN_VERTICAL.CENTER # Exercise name + position p2 = cells[1].paragraphs[0] r = p2.add_run(name + '\n') r.bold = True r.font.size = Pt(10) r.font.color.rgb = BLUE_DARK r2 = p2.add_run('Position: ' + position) r2.font.size = Pt(8.5) r2.font.color.rgb = RGBColor(0x66, 0x66, 0x66) r2.italic = True # Instructions p3 = cells[2].paragraphs[0] r3 = p3.add_run(instructions) r3.font.size = Pt(9) # Reps p4 = cells[3].paragraphs[0] r4 = p4.add_run(reps) r4.font.size = Pt(9) r4.bold = True p4.alignment = WD_ALIGN_PARAGRAPH.CENTER # Frequency p5 = cells[4].paragraphs[0] r5 = p5.add_run(freq) r5.font.size = Pt(9) p5.alignment = WD_ALIGN_PARAGRAPH.CENTER # Alternate row shading if num % 2 == 0: for c in cells[1:]: shade_cell(c, 'F4F6F8') else: for c in cells[1:]: shade_cell(c, 'FFFFFF') # ═══════════════════════════════════════════════════════════════════════════════ # HEADER BANNER # ═══════════════════════════════════════════════════════════════════════════════ banner_table = doc.add_table(rows=1, cols=1) banner_table.alignment = WD_TABLE_ALIGNMENT.CENTER cell = banner_table.cell(0, 0) shade_cell(cell, '004E9A') p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(10) p.paragraph_format.space_after = Pt(2) r = p.add_run('🦵 HOME EXERCISE PROGRAMME') r.bold = True r.font.size = Pt(18) r.font.color.rgb = WHITE r.font.name = 'Arial' p2 = cell.add_paragraph() p2.alignment = WD_ALIGN_PARAGRAPH.CENTER p2.paragraph_format.space_before = Pt(0) p2.paragraph_format.space_after = Pt(10) r2 = p2.add_run('After Total Knee Replacement (TKR) Surgery') r2.font.size = Pt(13) r2.font.color.rgb = RGBColor(0xCC, 0xE4, 0xFF) r2.font.name = 'Arial' # ── Patient info row ────────────────────────────────────────────────────────── info_table = doc.add_table(rows=1, cols=4) info_table.alignment = WD_TABLE_ALIGNMENT.CENTER shade_cell(info_table.cell(0,0), 'D6EBF7') shade_cell(info_table.cell(0,1), 'FFFFFF') shade_cell(info_table.cell(0,2), 'D6EBF7') shade_cell(info_table.cell(0,3), 'FFFFFF') labels = ['Patient Name:', '', 'Date of Surgery:', ''] for i, lbl in enumerate(labels): cell = info_table.cell(0, i) p = cell.paragraphs[0] p.paragraph_format.space_before = Pt(4) p.paragraph_format.space_after = Pt(4) run = p.add_run(lbl) run.bold = True run.font.size = Pt(9) run.font.color.rgb = BLUE_DARK para_space(doc, before=4, after=0) # ── Intro box ───────────────────────────────────────────────────────────────── intro_tbl = doc.add_table(rows=1, cols=1) shade_cell(intro_tbl.cell(0,0), 'EBF5FF') set_cell_border(intro_tbl.cell(0,0), val='single', sz='6', color='007BC2') ip = intro_tbl.cell(0,0).paragraphs[0] ip.paragraph_format.space_before = Pt(6) ip.paragraph_format.space_after = Pt(6) ir = ip.add_run( 'These exercises are an essential part of your recovery. ' 'Do them every day. They reduce swelling, restore movement, ' 'strengthen your muscles, and help you return to normal activities. ' 'If any exercise causes severe pain that does not settle within 30 minutes, ' 'stop and contact your physiotherapist.' ) ir.font.size = Pt(9.5) ir.font.color.rgb = BLUE_DARK ir.font.name = 'Arial' para_space(doc, before=4, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 1 — WEEK 1-2 EXERCISES # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '📅 Week 1–2: Starting Exercises (Begin Day After Surgery)') p_note = doc.add_paragraph() p_note.paragraph_format.space_before = Pt(2) p_note.paragraph_format.space_after = Pt(4) rn = p_note.add_run('Start with 5 repetitions, 2× per day. Increase to 10 reps, 3-4× per day as pain allows.') rn.font.size = Pt(9) rn.font.color.rgb = RGBColor(0x44, 0x44, 0x44) rn.italic = True # Exercise table ex_table = doc.add_table(rows=1, cols=5) ex_table.style = 'Table Grid' # Header row hdr_cells = ex_table.rows[0].cells headers = ['#', 'Exercise', 'How To Do It', 'Reps', 'Times/Day'] widths = [Cm(0.9), Cm(3.8), Cm(7.5), Cm(1.8), Cm(2.0)] for i, (hdr, w) in enumerate(zip(headers, widths)): cell = hdr_cells[i] shade_cell(cell, '004E9A') p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run(hdr) r.bold = True r.font.size = Pt(9) r.font.color.rgb = WHITE cell.width = w cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER exercises_wk12 = [ (1, 'Ankle Pumps', 'Lying or sitting. Bend your foot up toward you, then point it down. Keep moving rhythmically.', '30 reps', 'Every hour'), (2, 'Quad Sets\n(Static Quads)', 'Lying flat. Push the back of your knee DOWN into the bed. Pull toes toward you. Hold 10 sec. Feel the thigh tighten.', '10 reps', '4× day'), (3, 'Straight Leg Raise (SLR)', 'Tighten thigh (as above). Keeping knee STRAIGHT, lift leg 6 inches off bed. Hold 5 sec. Lower slowly.', '10 reps', '3-4× day'), (4, 'Inner Range Quads', 'Place a firm rolled towel under your knee (about 30°). Lift your heel off the bed by straightening the knee fully. Hold 5 sec.', '10 reps', '3-4× day'), (5, 'Heel Slides', 'Lying flat. Slide your heel toward your bottom as far as comfortable. Hold 5 sec. Slide back.', '10 reps', '3-4× day'), (6, 'Static Glute Squeeze', 'Lying flat. Squeeze both buttock muscles together tightly. Hold 10 sec. Relax.', '10 reps', '3-4× day'), (7, 'Knee Extension\n(Full Range)', 'Sitting on chair. Pull toes up, tighten thigh and STRAIGHTEN the knee fully. Hold 10 sec. Lower slowly.', '10 reps', '3-4× day'), (8, 'Knee Flexion\nin Sitting', 'Sitting on edge of chair/bed. Bend the knee as far back as comfortable. Hold 8-10 sec. Repeat. Use good leg to gently assist if needed.', '10 reps', '3-4× day'), ] for ex in exercises_wk12: add_exercise_row(ex_table, *ex) # ─ Extension tip ───────────────────────────────────────────────────────────── para_space(doc, before=4, after=0) ext_tbl = doc.add_table(rows=1, cols=1) shade_cell(ext_tbl.cell(0,0), 'FFF3E0') set_cell_border(ext_tbl.cell(0,0), val='single', sz='6', color='E86A1A') ep = ext_tbl.cell(0,0).paragraphs[0] ep.paragraph_format.space_before = Pt(5) ep.paragraph_format.space_after = Pt(5) er1 = ep.add_run('⚠️ IMPORTANT: ') er1.bold = True er1.font.size = Pt(9.5) er1.font.color.rgb = ORANGE er2 = ep.add_run( 'Always rest with a firm pillow or roll under your HEEL — never under your knee. ' 'Full straightening (extension) of your knee is the most important early goal. ' 'A bent knee that does not straighten fully causes long-term walking problems.' ) er2.font.size = Pt(9.5) er2.font.name = 'Arial' para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 2 — WEEKS 2-6 # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '📅 Weeks 2–6: Progressive Exercises') p_note2 = doc.add_paragraph() p_note2.paragraph_format.space_before = Pt(2) p_note2.paragraph_format.space_after = Pt(4) rn2 = p_note2.add_run('Continue all Week 1-2 exercises AND add the following. Aim for 10 reps each, 3× per day.') rn2.font.size = Pt(9) rn2.font.color.rgb = RGBColor(0x44, 0x44, 0x44) rn2.italic = True ex_table2 = doc.add_table(rows=1, cols=5) ex_table2.style = 'Table Grid' hdr_cells2 = ex_table2.rows[0].cells for i, (hdr, w) in enumerate(zip(headers, widths)): cell = hdr_cells2[i] shade_cell(cell, '004E9A') p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run(hdr) r.bold = True r.font.size = Pt(9) r.font.color.rgb = WHITE cell.width = w cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER exercises_wk26 = [ (1, 'Short Arc Quads', 'Towel under knee. Slowly straighten knee from 30° to full extension. Hold 5 sec. Lower slowly. DO NOT swing.', '10 reps', '3× day'), (2, 'Mini Squats\n(Wall Support)', 'Stand with back lightly against wall. Feet shoulder-width apart. Slowly bend both knees to 30°. Hold 5 sec. Straighten up.', '10 reps', '3× day'), (3, 'Sit to Stand', 'Sit on a firm chair. Slide to front. Lean forward slightly. Push up using chair arms and your legs equally. Lower yourself back slowly.', '10 reps', '3× day'), (4, 'Heel Raises\n(Standing)', 'Hold something steady. Rise up on your toes. Hold 5 sec. Lower slowly. Start with both feet, progress to one foot.', '10 reps', '3× day'), (5, 'Step-Ups', 'Hold rail/wall. Step up onto a low step (10 cm) with operated leg first. Bring other leg up. Step down with operated leg last.', '10 reps', '2× day'), (6, 'Hip Abduction\n(Standing)', 'Hold for support. Lift operated leg out to the side, keeping toes pointing forward. Hold 3 sec. Lower.', '10 reps', '3× day'), (7, 'Hamstring Curls', 'Standing, hold support. Bend operated knee, bringing heel toward buttock. Hold 5 sec. Lower slowly.', '10 reps', '3× day'), (8, 'Single-Leg Balance', 'Hold support lightly. Balance on operated leg for 10-30 sec. Progress to no support as confidence grows.', '5 holds', '3× day'), ] for ex in exercises_wk26: add_exercise_row(ex_table2, *ex) para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 3 — WEEKS 6+ # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '📅 Week 6 and Beyond: Strengthening & Functional Exercises') p_note3 = doc.add_paragraph() p_note3.paragraph_format.space_before = Pt(2) p_note3.paragraph_format.space_after = Pt(4) rn3 = p_note3.add_run('Add these exercises when your physiotherapist advises. Continue all previous exercises.') rn3.font.size = Pt(9) rn3.font.color.rgb = RGBColor(0x44, 0x44, 0x44) rn3.italic = True ex_table3 = doc.add_table(rows=1, cols=5) ex_table3.style = 'Table Grid' hdr_cells3 = ex_table3.rows[0].cells for i, (hdr, w) in enumerate(zip(headers, widths)): cell = hdr_cells3[i] shade_cell(cell, '004E9A') p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run(hdr) r.bold = True r.font.size = Pt(9) r.font.color.rgb = WHITE cell.width = w cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER exercises_wk6plus = [ (1, 'Stationary Cycling', 'Start with seat high (minimal bend). Cycle forward 10 min. Gradually lower seat to increase knee bend over weeks.', '10-20 min', '1× day'), (2, 'Step-Downs\n(Eccentric)', 'Stand on step. Slowly lower operated leg toward floor, bending standing knee to 30°. Touch floor lightly. Return up.', '10 reps', '2× day'), (3, 'Partial Squats\n(0–60°)', 'Feet shoulder-width. Squat to 60° only. Keep knees over toes. Hold 5 sec. Rise slowly.', '10 reps', '2-3× day'), (4, 'Lateral Band Walks', 'Light resistance band around ankles. Sidestep 10 steps right, 10 steps left. Keep knees slightly bent.', '3 sets', '2× day'), (5, 'Swimming / Aqua Walking', 'Once wound fully healed (6-8 wks). Walk in chest-deep water. Warm pool preferred. Excellent for pain-free strengthening.', '20-30 min', '3× week'), (6, 'Walking Programme', 'Increase distance daily. Start on flat. Progress to gentle inclines. Stop before pain develops. Rest, ice, elevate after.', 'As able', 'Daily'), ] for ex in exercises_wk6plus: add_exercise_row(ex_table3, *ex) para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 4 — ROM GOALS # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '🎯 Range of Movement Targets') rom_table = doc.add_table(rows=5, cols=4) rom_table.style = 'Table Grid' rom_data = [ ('Timeframe', 'Bend (Flexion)', 'Straighten (Extension)', 'Milestone'), ('Week 1-2', '80-90°', '0° (full)', 'Walk with frame/crutches'), ('Week 2-6', '100-110°', '0° (full)', 'Walk independently at home'), ('3 Months', '120°+', '0° (full)', 'Stairs, driving, light work'), ('6-12 Months','120-135°', '0° (full)', 'Full daily activities'), ] rom_colors = ['004E9A', 'FFFFFF', 'F4F6F8', 'FFFFFF', 'F4F6F8'] rom_font_colors = [WHITE, None, None, None, None] for r_idx, (row_data, bg, fc) in enumerate(zip(rom_data, rom_colors, rom_font_colors)): row = rom_table.rows[r_idx] for c_idx, text in enumerate(row_data): cell = row.cells[c_idx] shade_cell(cell, bg) p = cell.paragraphs[0] p.paragraph_format.space_before = Pt(3) p.paragraph_format.space_after = Pt(3) p.alignment = WD_ALIGN_PARAGRAPH.CENTER run = p.add_run(text) run.font.size = Pt(9) run.font.name = 'Arial' if r_idx == 0: run.bold = True run.font.color.rgb = WHITE elif c_idx == 2 and r_idx > 0: run.bold = True run.font.color.rgb = GREEN para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 5 — SWELLING & PAIN MANAGEMENT # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '🧊 Managing Pain and Swelling at Home') tips_table = doc.add_table(rows=1, cols=2) tips_table.alignment = WD_TABLE_ALIGNMENT.CENTER shade_cell(tips_table.cell(0,0), 'E8F5E9') shade_cell(tips_table.cell(0,1), 'FFF3E0') # Left: ICE lp = tips_table.cell(0,0).paragraphs[0] lp.paragraph_format.space_before = Pt(5) lp.paragraph_format.space_after = Pt(5) lr1 = lp.add_run('🧊 ICE THERAPY\n') lr1.bold = True lr1.font.size = Pt(10) lr1.font.color.rgb = BLUE_MID lr2 = lp.add_run( '• Wrap ice or frozen peas in a damp towel\n' '• Apply to knee for 15-20 minutes\n' '• Repeat 3-4 times per day\n' '• Always use a towel – never ice direct on skin\n' '• Ice AFTER exercises for best effect' ) lr2.font.size = Pt(9) # Right: ELEVATION rp = tips_table.cell(0,1).paragraphs[0] rp.paragraph_format.space_before = Pt(5) rp.paragraph_format.space_after = Pt(5) rr1 = rp.add_run('⬆️ ELEVATION\n') rr1.bold = True rr1.font.size = Pt(10) rr1.font.color.rgb = ORANGE rr2 = rp.add_run( '• Rest with leg raised above heart level\n' '• Place pillow under HEEL — not under knee\n' '• Keep knee as straight as possible when resting\n' '• Elevate for 20-30 min after exercise\n' '• Avoid prolonged sitting with knee bent' ) rr2.font.size = Pt(9) para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 6 — DO / DON'T # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '✅ Do\'s and ❌ Don\'ts') dd_table = doc.add_table(rows=7, cols=2) dd_table.style = 'Table Grid' do_data = [ ('✅ DO', '❌ DO NOT'), ('Do your exercises every single day', 'Place a pillow under your knee when resting'), ('Keep the leg elevated when not walking', 'Kneel on the operated knee without a pad'), ('Ice the knee after exercises and when swollen', 'Force the knee into painful positions'), ('Walk little and often, increasing daily', 'Cross your legs'), ('Take pain relief as prescribed before exercises', 'Sit in low chairs or soft sofas in early weeks'), ('Keep surgeon/physio appointments', 'Drive until your surgeon gives the all-clear'), ] dd_colors_left = ['004E9A', 'E8F5E9', 'FFFFFF', 'E8F5E9', 'FFFFFF', 'E8F5E9', 'FFFFFF'] dd_colors_right = ['004E9A', 'FFEBEE', 'FFFFFF', 'FFEBEE', 'FFFFFF', 'FFEBEE', 'FFFFFF'] for r_idx, (left, right) in enumerate(dd_data): row = dd_table.rows[r_idx] shade_cell(row.cells[0], dd_colors_left[r_idx]) shade_cell(row.cells[1], dd_colors_right[r_idx]) for c_idx, (cell, text) in enumerate([(row.cells[0], left), (row.cells[1], right)]): p = cell.paragraphs[0] p.paragraph_format.space_before = Pt(4) p.paragraph_format.space_after = Pt(4) run = p.add_run(text) run.font.size = Pt(9) run.font.name = 'Arial' if r_idx == 0: run.bold = True run.font.color.rgb = WHITE elif c_idx == 0: run.font.color.rgb = GREEN else: run.font.color.rgb = ORANGE para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 7 — RED FLAGS # ═══════════════════════════════════════════════════════════════════════════════ red_tbl = doc.add_table(rows=1, cols=1) shade_cell(red_tbl.cell(0,0), 'FFEBEE') set_cell_border(red_tbl.cell(0,0), val='single', sz='8', color='C62828') rp2 = red_tbl.cell(0,0).paragraphs[0] rp2.paragraph_format.space_before = Pt(6) rp2.paragraph_format.space_after = Pt(6) rr_1 = rp2.add_run('🚨 SEEK URGENT MEDICAL ATTENTION IF YOU NOTICE:\n') rr_1.bold = True rr_1.font.size = Pt(10) rr_1.font.color.rgb = RGBColor(0xC6, 0x28, 0x28) rr_2 = rp2.add_run( '• Sudden severe pain, redness, or warmth in the calf (possible DVT / blood clot)\n' '• Chest pain, shortness of breath, or coughing blood (possible PE)\n' '• Fever above 38°C, chills, or the wound feels hot and discharges pus (possible infection)\n' '• The knee gives way or you feel a "clunk" / sudden instability\n' '• Wound edges separate or drainage through the dressing does not stop' ) rr_2.font.size = Pt(9.5) rr_2.font.name = 'Arial' para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 8 — STAIR TECHNIQUE & WALKING AIDS # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '🪜 Stairs, Walking Aids & Daily Tips') stair_tbl = doc.add_table(rows=1, cols=2) shade_cell(stair_tbl.cell(0,0), 'E3F2FD') shade_cell(stair_tbl.cell(0,1), 'F3E5F5') sp1 = stair_tbl.cell(0,0).paragraphs[0] sp1.paragraph_format.space_before = Pt(5) sp1.paragraph_format.space_after = Pt(5) sr1 = sp1.add_run('🪜 STAIRS\n') sr1.bold = True sr1.font.size = Pt(10) sr1.font.color.rgb = BLUE_MID sr2 = sp1.add_run( 'GOING UP:\n' '"Good leg goes UP first"\n' '(Good leg → Operated leg → Crutch)\n\n' 'GOING DOWN:\n' '"Bad leg goes DOWN first"\n' '(Crutch → Operated leg → Good leg)\n\n' 'Always use the handrail!' ) sr2.font.size = Pt(9) sp2 = stair_tbl.cell(0,1).paragraphs[0] sp2.paragraph_format.space_before = Pt(5) sp2.paragraph_format.space_after = Pt(5) sr3 = sp2.add_run('🚶 WALKING AIDS\n') sr3.bold = True sr3.font.size = Pt(10) sr3.font.color.rgb = BLUE_MID sr4 = sp2.add_run( 'Frame → 2 Crutches → 1 Stick → None\n\n' '• Wean aids as pain and confidence improve\n' '• Use 1 stick on the OPPOSITE side\n' ' to your operated knee\n' '• Continue using aid outdoors until\n' ' you walk without a limp\n' '• Do NOT rush — use aids as long as needed' ) sr4.font.size = Pt(9) para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # SECTION 9 — RETURN TO ACTIVITIES TIMELINE # ═══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '📆 Return to Activities Timeline') act_table = doc.add_table(rows=9, cols=2) act_table.style = 'Table Grid' act_data = [ ('Activity', 'Approximate Timeframe'), ('Walking indoors unaided', '2-4 weeks'), ('Light housework', '3-6 weeks'), ('Driving (right knee / automatic)', '6-8 weeks (surgeon approval)'), ('Driving (left knee / manual)', '10-12 weeks (surgeon approval)'), ('Office/sedentary work', '6-8 weeks'), ('Physical/standing work', '3-6 months'), ('Swimming (wound healed)', '6-8 weeks'), ('Cycling, golf, gentle hiking', '3-4 months'), ] for r_idx, (act, time) in enumerate(act_data): row = act_table.rows[r_idx] if r_idx == 0: shade_cell(row.cells[0], '004E9A') shade_cell(row.cells[1], '004E9A') fc_act = WHITE elif r_idx % 2 == 0: shade_cell(row.cells[0], 'F4F6F8') shade_cell(row.cells[1], 'F4F6F8') fc_act = None else: shade_cell(row.cells[0], 'FFFFFF') shade_cell(row.cells[1], 'FFFFFF') fc_act = None for cell, text in [(row.cells[0], act), (row.cells[1], time)]: p = cell.paragraphs[0] p.paragraph_format.space_before = Pt(3) p.paragraph_format.space_after = Pt(3) run = p.add_run(text) run.font.size = Pt(9) run.font.name = 'Arial' if r_idx == 0: run.bold = True run.font.color.rgb = WHITE elif fc_act: run.font.color.rgb = fc_act para_space(doc, before=6, after=0) # ═══════════════════════════════════════════════════════════════════════════════ # FOOTER # ═══════════════════════════════════════════════════════════════════════════════ footer_tbl = doc.add_table(rows=1, cols=1) shade_cell(footer_tbl.cell(0,0), '004E9A') fp = footer_tbl.cell(0,0).paragraphs[0] fp.alignment = WD_ALIGN_PARAGRAPH.CENTER fp.paragraph_format.space_before = Pt(6) fp.paragraph_format.space_after = Pt(6) fp.add_run('Physiotherapist: ___________________________ ') fp.add_run('Contact: ___________________________ ') fp.add_run('Next Appointment: ___________________') for run in fp.runs: run.font.size = Pt(8.5) run.font.color.rgb = WHITE run.font.name = 'Arial' # ── Save ────────────────────────────────────────────────────────────────────── out_path = '/tmp/workspace/tkr-handout/Post_TKR_Home_Exercise_Handout.docx' doc.save(out_path) print(f"Saved: {out_path}") PYEOF echo "Script written."
cd /tmp/workspace/tkr-handout && python3 create_handout.py
python3 -c "from docx.shared import RGBColor; c = RGBColor(0x00, 0x7B, 0xC2); print(dir(c)); print(type(c))"
~/tkr-handout/create_handout.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/tkr-handout/create_handout.py'
cd /tmp/workspace/tkr-handout && python3 create_handout.py
python3 -c " exercises_wk12 = [ (1, 'Ankle Pumps', 'Lying or sitting. Bend your foot up toward you, then point it down. Keep moving rhythmically.', '30 reps', 'Every hour'), (2, 'Quad Sets', 'Lying flat. Push the back of your knee DOWN into the bed. Pull toes toward you. Hold 10 sec.', '10 reps', '4x day'), ] for ex in exercises_wk12: print(len(ex), ex) "
~/tkr-handout/create_handout.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/tkr-handout/create_handout.py'
cd /tmp/workspace/tkr-handout && python3 create_handout.py 2>&1
cd /tmp/workspace/tkr-handout && sed -i 's/for r_idx, (left, right) in enumerate(dd_data):/for r_idx, (left, right) in enumerate(do_data):/' create_handout.py && python3 create_handout.py 2>&1
ls -lh /tmp/workspace/tkr-handout/Post_TKR_Home_Exercise_Handout.docx
Post TKR Home Exercise Handout
Word Document · DOCX