@@ -935,6 +935,9 @@ <h3>Guidelines</h3>
935935 let completedFingers = new Set ( ) ;
936936 let fingerPositionData = [ ] ;
937937 let nonTargetFingerMovements = 0 ;
938+ let baselineFingerPositions = { } ;
939+ let cumulativeFingerMovement = { } ;
940+ let independenceFrameCount = 0 ;
938941
939942 // Enhanced touch detection parameters
940943 const TOUCH_THRESHOLD = 0.08 ; // Slightly more forgiving threshold
@@ -1185,10 +1188,36 @@ <h3>Guidelines</h3>
11851188 currentlyTouching . add ( fingerLandmark ) ;
11861189 }
11871190
1188- // Track unwanted movements in non-target fingers (slightly more forgiving)
1189- if ( ! requiredFingers . has ( fingerLandmark ) && distance < 0.14 ) {
1190- nonTargetFingerMovements ++ ;
1191+ // Track real finger independence - measure unwanted movement in non-target fingers
1192+ if ( ! requiredFingers . has ( fingerLandmark ) ) {
1193+ // Initialize baseline if this is early in the task (first 500ms)
1194+ const taskTime = Date . now ( ) - combinationStartTime ;
1195+ if ( taskTime < 500 && ! baselineFingerPositions [ fingerLandmark ] ) {
1196+ baselineFingerPositions [ fingerLandmark ] = {
1197+ x : fingerTip . x ,
1198+ y : fingerTip . y ,
1199+ z : fingerTip . z
1200+ } ;
1201+ cumulativeFingerMovement [ fingerLandmark ] = 0 ;
1202+ }
1203+
1204+ // Measure movement from baseline for non-target fingers
1205+ if ( baselineFingerPositions [ fingerLandmark ] ) {
1206+ const baseline = baselineFingerPositions [ fingerLandmark ] ;
1207+ const movementFromBaseline = Math . sqrt (
1208+ Math . pow ( fingerTip . x - baseline . x , 2 ) +
1209+ Math . pow ( fingerTip . y - baseline . y , 2 ) +
1210+ Math . pow ( ( fingerTip . z - baseline . z ) * 0.3 , 2 ) // Weight Z less
1211+ ) ;
1212+
1213+ // Accumulate unwanted movement (anything > 0.03 is considered unwanted movement)
1214+ if ( movementFromBaseline > 0.03 ) {
1215+ cumulativeFingerMovement [ fingerLandmark ] += movementFromBaseline ;
11911216 }
1217+ }
1218+ }
1219+
1220+ independenceFrameCount ++ ;
11921221 } ) ;
11931222
11941223 // Store finger position data for analysis
@@ -1362,8 +1391,11 @@ <h3>Guidelines</h3>
13621391
13631392 function nextCombination ( ) {
13641393 // Calculate finger independence score
1365- const independenceScore = Math . max ( 0 , 100 - ( nonTargetFingerMovements / 10 ) ) ; // Penalty for unwanted movements
1366-
1394+ // Calculate true finger independence score based on unwanted movements
1395+ const totalUnwantedMovement = Object . values ( cumulativeFingerMovement ) . reduce ( ( sum , movement ) => sum + movement , 0 ) ;
1396+ const avgUnwantedMovement = independenceFrameCount > 0 ? totalUnwantedMovement / independenceFrameCount : 0 ;
1397+ const independenceScore = Math . max ( 0 , 100 - ( avgUnwantedMovement * 500 ) ) ; // Scale penalty appropriately// Penalty for unwanted movements
1398+
13671399 // Calculate comprehensive result metrics
13681400 const completionTime = Date . now ( ) - combinationStartTime ;
13691401 const accuracyScore = Math . max ( 0 , 100 - ( wrongTouchCount * 15 ) ) ; // 15% penalty per wrong touch
@@ -1434,14 +1466,18 @@ <h3>Guidelines</h3>
14341466 nonTargetFingerMovements = 0 ;
14351467 detectionFrames = [ ] ;
14361468 fingerPositionData = [ ] ;
1437- combinationCompleted = false ; // Reset completion state
1438- completedFingers = new Set ( ) ; // Reset completed fingers
1469+ combinationCompleted = false ;
1470+ completedFingers = new Set ( ) ;
1471+
1472+ // Reset finger independence tracking
1473+ baselineFingerPositions = { } ;
1474+ cumulativeFingerMovement = { } ;
1475+ independenceFrameCount = 0 ;
14391476
14401477 // Update UI
14411478 document . getElementById ( 'progress-display' ) . textContent = `${ currentCombinationIndex + 1 } /15` ;
14421479 document . getElementById ( 'combination-text' ) . textContent = currentCombination . name ;
14431480 }
1444-
14451481 function startRecording ( ) {
14461482 if ( ! handDetected ) {
14471483 alert ( 'Please position your hand in view of the camera before starting.' ) ;
@@ -1671,16 +1707,22 @@ <h1>Assessment Complete!</h1>
16711707 }
16721708
16731709
1674- function createRanking ( results ) {
1675- return results
1676- . map ( result => {
1677- // Advanced ranking score: accuracy (40%) + speed (30%) + independence (30%)
1678- const rankingScore = result . overallScore ;
1679- return { ...result , rankingScore } ;
1680- } )
1681- . sort ( ( a , b ) => b . rankingScore - a . rankingScore ) ;
1682- }
1683-
1710+ function createRanking ( results ) {
1711+ return results
1712+ . map ( result => {
1713+ // Base performance score
1714+ const baseScore = ( result . accuracyScore * 0.4 ) + ( result . speedScore * 0.3 ) + ( result . independenceScore * 0.3 ) ;
1715+
1716+ // Neurologically-informed difficulty weights (much more modest)
1717+ const fingerCount = result . combination . fingers . length ;
1718+ const difficultyWeight = 1.0 + ( fingerCount - 1 ) * 0.05 ; // 1.0, 1.05, 1.10, 1.15 instead of 1.67x-2.67x
1719+
1720+ const rankingScore = baseScore * difficultyWeight ;
1721+ return { ...result , rankingScore } ;
1722+ } )
1723+ . sort ( ( a , b ) => b . rankingScore - a . rankingScore ) ;
1724+ }
1725+
16841726function generateResultsHTML ( rightRanking , leftRanking , overallStats ) {
16851727 console . log ( "Generating compact results HTML..." ) ;
16861728
0 commit comments