Functional Movement Screening Tool

Functional Movement Screening Tool

Assess your movement patterns to identify limitations and asymmetries.

${instructions}

Scoring Criteria

${scoring}

Enter Your Score

${scoringOptions}
`; switch (id) { case 'welcome': return `

Welcome to the FMS Tool

This tool guides you through 7 fundamental movement patterns. Perform each test as described and score yourself honestly. If you feel any pain during a test, assign a score of 0 and do not continue that test. Use the 'Next' button to proceed.

Disclaimer: This is not a medical diagnosis. Consult a professional for any health concerns.

`; case 'deep-squat': return testTemplate('Deep Squat', 'Hold a dowel overhead with arms extended. Stand with feet shoulder-width apart and squat as deeply as possible while keeping the dowel overhead.', '
  • 3: Torso parallel with tibia, dowel aligned over feet.
  • 2: Heels come off the floor.
  • 1: Loss of balance or inability to achieve full depth.
', 'e.g., Heels lifted slightly.'); case 'hurdle-step': return testTemplate('Hurdle Step', 'Step over a string set at your knee height without touching it, maintaining balance. Perform on both legs.', '
  • 3: Hips, knees, and ankles remain aligned in the sagittal plane.
  • 2: Alignment is lost; movement in the frontal plane.
  • 1: Inability to clear the hurdle or loss of balance.
', 'Score the weaker side. e.g., Left leg score: 2'); case 'inline-lunge': return testTemplate('Inline Lunge', 'Stand on a line with one foot in front of the other. Lunge straight down so your back knee touches the line, keeping your feet straight. Perform on both legs.', '
  • 3: Minimal torso movement, feet remain on the line.
  • 2: Torso moves, feet come off the line.
  • 1: Loss of balance.
', 'Score the weaker side. e.g., Right leg unstable.'); case 'shoulder-mobility': return testTemplate('Shoulder Mobility', 'Make a fist with each hand. Reach one hand over your shoulder and the other up your back, trying to get your fists as close as possible. Measure and repeat on the other side.', '
  • 3: Fists are within one hand length of each other.
  • 2: Fists are within one and a half hand lengths.
  • 1: Fists are more than one and a half hand lengths apart.
', 'Score the more limited side. e.g., Right shoulder tighter.'); case 'leg-raise': return testTemplate('Active Straight-Leg Raise', 'Lie flat on your back. Raise one leg as high as possible without bending the knee, while the other leg remains flat on the ground. Perform on both legs.', '
  • 3: Ankle passes the vertical line of the mid-thigh.
  • 2: Ankle is between mid-thigh and knee.
  • 1: Ankle does not pass the knee.
', 'Score the weaker side.'); case 'push-up': return testTemplate('Trunk Stability Push-up', 'Perform a push-up while keeping your body in a straight line from shoulders to ankles, without your back sagging.', '
  • 3: Body lifts as one unit. (Men: thumbs at forehead; Women: thumbs at chin)
  • 2: Body lifts as one unit. (Men: thumbs at chin; Women: thumbs at clavicle)
  • 1: Inability to perform a push-up with proper form.
'); case 'rotary-stability': return testTemplate('Rotary Stability', 'From a hands-and-knees position, extend your same-side arm and leg without losing balance. Repeat on the other side.', '
  • 3: Performs a correct unilateral repetition.
  • 2: Performs a correct diagonal repetition (opposite arm/leg).
  • 1: Inability to perform a diagonal repetition.
', 'Score the weaker side.'); case 'results': return `

Screening Complete

Click the button below to calculate and view your results.

`; default: return ''; } } // --- Tab Navigation & Scoring --- function showTab(tabIndex) { document.querySelectorAll('.tab-btn').forEach((btn, index) => btn.classList.toggle('active', index === tabIndex)); document.querySelectorAll('.tab-content').forEach((content, index) => content.classList.toggle('active', index === tabIndex)); state.currentTabIndex = tabIndex; prevBtn.disabled = state.currentTabIndex === 0; nextBtn.disabled = state.currentTabIndex === screens.length - 1; } function handleScoreChange(e) { state.scores[e.target.name] = parseInt(e.target.value); } function calculateAndShowResults() { let totalScore = 0; const lowScores = []; screens.slice(1, -1).forEach(screen => { const score = state.scores[screen.id]; if (typeof score === 'number') { totalScore += score; if (score <= 1) { lowScores.push(screen.title); } } }); let interpretation = ''; if (totalScore <= 14) { interpretation = 'Your score is 14 or below, which may indicate an increased risk for injury. Focus on the areas with low scores.'; } else { interpretation = 'Your score suggests a good foundation of movement. Continue to work on any areas where you scored a 2.'; } if (lowScores.some(s => s.includes('0'))) { interpretation += ' Pain was noted during the screen. It is highly recommended to consult a healthcare professional.'; } const resultsContent = document.getElementById('results-content'); resultsContent.innerHTML = `

Total Score: ${totalScore} / 21

${interpretation}

${lowScores.length > 0 ? `

Areas for Focus:

${lowScores.join(', ')}

` : ''}
`; resultsContent.style.display = 'block'; document.getElementById('download-pdf-btn').addEventListener('click', generatePDF); } // --- PDF Generation --- async function generatePDF() { const { jsPDF } = window.jspdf; const downloadBtn = document.getElementById('download-pdf-btn'); const originalButtonText = downloadBtn.textContent; downloadBtn.textContent = 'Generating...'; downloadBtn.disabled = true; const pdfWrapper = document.createElement('div'); pdfWrapper.style.position = 'absolute'; pdfWrapper.style.left = '-9999px'; pdfWrapper.style.top = '0'; pdfWrapper.style.width = '800px'; pdfWrapper.style.backgroundColor = 'white'; pdfWrapper.className = 'p-8'; let reportHtml = `

Functional Movement Screen Report

${new Date().toLocaleDateString()}

${document.getElementById('results-content').innerHTML}

Detailed Scores

`; screens.slice(1, -1).forEach(screen => { const score = state.scores[screen.id] ?? 'N/A'; const notes = document.querySelector(`[data-id="${screen.id}"] textarea`).value || ''; reportHtml += ``; }); reportHtml += `
TestScoreNotes
${screen.title}${score}${notes}
`; pdfWrapper.innerHTML = reportHtml; pdfWrapper.querySelector('#download-pdf-btn').remove(); document.body.appendChild(pdfWrapper); try { const canvas = await html2canvas(pdfWrapper, { scale: 2, useCORS: true, logging: false }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const imgWidth = canvas.width; const imgHeight = canvas.height; const ratio = imgWidth / imgHeight; let finalImgWidth = pdfWidth; let finalImgHeight = pdfWidth / ratio; if (finalImgHeight > pdfHeight) { finalImgHeight = pdfHeight; finalImgWidth = pdfHeight * ratio; } pdf.addImage(imgData, 'PNG', 0, 0, finalImgWidth, finalImgHeight); pdf.save('FMS-Report.pdf'); } catch (error) { console.error("PDF Generation Error:", error); } finally { document.body.removeChild(pdfWrapper); downloadBtn.textContent = originalButtonText; downloadBtn.disabled = false; } } // --- Event Listeners --- prevBtn.addEventListener('click', () => { if (state.currentTabIndex > 0) showTab(state.currentTabIndex - 1); }); nextBtn.addEventListener('click', () => { if (state.currentTabIndex < screens.length - 1) showTab(state.currentTabIndex + 1); }); // --- Initial Call --- initializeUI(); });
Scroll to Top