ariG23498 HF Staff commited on
Commit
ad41710
·
verified ·
1 Parent(s): f7e8d8a

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +239 -42
index.html CHANGED
@@ -583,14 +583,179 @@
583
  }
584
  }
585
 
586
- // Common words for drill generation
587
- const COMMON_WORDS = [
588
- 'the', 'and', 'for', 'are', 'but', 'not', 'you', 'all', 'can', 'had',
589
- 'her', 'was', 'one', 'our', 'out', 'day', 'get', 'has', 'him', 'how',
590
- 'its', 'may', 'new', 'now', 'old', 'see', 'two', 'way', 'who', 'boy',
591
- 'did', 'car', 'let', 'put', 'say', 'she', 'too', 'use'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  ];
593
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
594
  // Keyboard layout
595
  const KEY_ROWS = [
596
  ['q','w','e','r','t','y','u','i','o','p'],
@@ -716,56 +881,88 @@
716
  });
717
  }
718
 
719
- function generateDrill(posteriors, length = 40){
 
720
  if (tracker.totalObservations < 20) {
721
- return "Type the target text above to build your personalized error model...";
 
722
  }
723
 
724
- // Calculate focus scores
725
- const scores = Object.entries(posteriors)
726
  .filter(([k, v]) => v.count > 0)
727
  .map(([k, v]) => ({
728
- key: k,
729
  focus: v.mean * (v.sd + 0.1),
730
- mean: v.mean,
731
- sd: v.sd
732
- }));
733
-
734
- scores.sort((a, b) => b.focus - a.focus);
 
 
735
 
736
- // Get top problematic keys
737
- const topKeys = scores.slice(0, Math.min(5, scores.length));
738
- if (topKeys.length === 0) return "Great job! Keep practicing to maintain your skills.";
739
 
740
- // Generate drill text
741
- let drill = "";
742
- const targetLength = length;
 
 
 
 
 
 
 
743
 
744
- while (drill.length < targetLength) {
745
- // 70% chance to use a word containing problem keys
746
- if (Math.random() < 0.7 && topKeys.length > 0) {
747
- const targetKey = topKeys[Math.floor(Math.random() * topKeys.length)];
748
- const wordsWithKey = COMMON_WORDS.filter(w => w.includes(targetKey.key));
 
 
 
 
 
 
 
 
 
 
 
 
749
 
750
- if (wordsWithKey.length > 0) {
751
- drill += wordsWithKey[Math.floor(Math.random() * wordsWithKey.length)] + " ";
752
- } else {
753
- // If no common word contains the key, create a simple pattern
754
- const patterns = [
755
- targetKey.key + targetKey.key,
756
- targetKey.key + "a" + targetKey.key,
757
- targetKey.key + "e" + targetKey.key,
758
- "a" + targetKey.key + "a"
759
- ];
760
- drill += patterns[Math.floor(Math.random() * patterns.length)] + " ";
761
  }
 
 
 
 
 
762
  } else {
763
- // Add a random common word
764
- drill += COMMON_WORDS[Math.floor(Math.random() * COMMON_WORDS.length)] + " ";
 
 
 
 
765
  }
766
  }
 
 
 
 
 
 
 
 
767
 
768
- return drill.trim();
769
  }
770
 
771
  function updateExplanation(posteriors){
@@ -867,7 +1064,7 @@
867
  updateHeatmap(post);
868
  updateExplanation(post);
869
 
870
- const drillText = generateDrill(post, 50);
871
  drillDiv.textContent = drillText;
872
 
873
  updateStats(post);
 
583
  }
584
  }
585
 
586
+ // Common words organized by difficulty and letter patterns
587
+ const WORD_CORPUS = {
588
+ // High-frequency words (top 100 most common)
589
+ common: [
590
+ 'the', 'and', 'for', 'are', 'but', 'not', 'you', 'all', 'would', 'her',
591
+ 'was', 'one', 'our', 'out', 'day', 'had', 'has', 'his', 'how', 'man',
592
+ 'its', 'say', 'she', 'which', 'their', 'time', 'will', 'way', 'about',
593
+ 'many', 'then', 'them', 'write', 'like', 'these', 'long', 'make', 'thing',
594
+ 'see', 'him', 'two', 'look', 'more', 'go', 'come', 'number', 'sound',
595
+ 'most', 'people', 'over', 'know', 'water', 'than', 'call', 'first'
596
+ ],
597
+ // Words with common digraphs
598
+ digraphs: {
599
+ 'th': ['the', 'that', 'this', 'they', 'there', 'think', 'through', 'three', 'thanks', 'thought'],
600
+ 'ch': ['change', 'check', 'choice', 'choose', 'chair', 'chance', 'charge', 'cheap', 'church', 'chapter'],
601
+ 'sh': ['should', 'show', 'share', 'short', 'shape', 'sharp', 'shift', 'shine', 'shock', 'shoot'],
602
+ 'wh': ['what', 'when', 'where', 'which', 'while', 'white', 'whole', 'whose', 'wheel', 'whether'],
603
+ 'qu': ['quick', 'quite', 'quiet', 'queen', 'question', 'quality', 'quarter', 'square', 'require', 'equal'],
604
+ 'ing': ['thing', 'being', 'doing', 'going', 'making', 'taking', 'coming', 'looking', 'working', 'thinking'],
605
+ 'er': ['other', 'after', 'never', 'every', 'under', 'number', 'perhaps', 'better', 'together', 'remember'],
606
+ 'ed': ['called', 'looked', 'asked', 'needed', 'wanted', 'worked', 'lived', 'turned', 'started', 'seemed']
607
+ },
608
+ // Words by difficulty (based on hand movements)
609
+ patterns: {
610
+ homeRow: ['had', 'ask', 'dad', 'sad', 'lad', 'fad', 'gas', 'has', 'lag', 'sag'],
611
+ topRow: ['were', 'your', 'trip', 'quit', 'power', 'write', 'quiet', 'worry', 'pretty', 'twenty'],
612
+ bottomRow: ['can', 'man', 'been', 'came', 'name', 'mean', 'become', 'common', 'woman', 'human'],
613
+ mixed: ['their', 'would', 'about', 'there', 'think', 'which', 'people', 'could', 'other', 'after']
614
+ },
615
+ // Common programming/tech words
616
+ technical: [
617
+ 'function', 'variable', 'return', 'class', 'import', 'export', 'const', 'async', 'array', 'object',
618
+ 'string', 'number', 'boolean', 'interface', 'public', 'private', 'static', 'method', 'property'
619
+ ]
620
+ };
621
+
622
+ // Sentence templates for more natural practice
623
+ const SENTENCE_TEMPLATES = [
624
+ "The {adjective} {noun} {verb} {preposition} the {noun}.",
625
+ "{pronoun} {verb} to {verb} the {adjective} {noun}.",
626
+ "Can you {verb} the {noun} {preposition} the {adjective} {noun}?",
627
+ "{number} {adjective} {noun}s {verb} {adverb} {preposition} the {noun}.",
628
+ "The {noun} {verb} {adjective} and {adjective}."
629
  ];
630
 
631
+ const WORD_TYPES = {
632
+ adjective: ['quick', 'brown', 'lazy', 'beautiful', 'small', 'large', 'happy', 'sad', 'fast', 'slow'],
633
+ noun: ['fox', 'dog', 'cat', 'house', 'tree', 'book', 'computer', 'phone', 'desk', 'chair'],
634
+ verb: ['jumps', 'runs', 'walks', 'sits', 'stands', 'writes', 'reads', 'types', 'thinks', 'works'],
635
+ pronoun: ['I', 'you', 'he', 'she', 'we', 'they', 'it'],
636
+ preposition: ['over', 'under', 'beside', 'through', 'across', 'behind', 'near', 'between'],
637
+ adverb: ['quickly', 'slowly', 'carefully', 'happily', 'quietly', 'loudly'],
638
+ number: ['two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']
639
+ };
640
+
641
+ // Enhanced drill generator
642
+ function generateDrill(posteriors, length = 50) {
643
+ if (tracker.totalObservations < 20) {
644
+ // Start with common words for beginners
645
+ return "Type these common words: the quick brown fox jumps over the lazy dog. Practice makes perfect!";
646
+ }
647
+
648
+ // Calculate focus scores for each letter
649
+ const letterScores = Object.entries(posteriors)
650
+ .filter(([k, v]) => v.count > 0)
651
+ .map(([k, v]) => ({
652
+ key: k,
653
+ focus: v.mean * (v.sd + 0.1),
654
+ errorRate: v.mean,
655
+ uncertainty: v.sd
656
+ }))
657
+ .sort((a, b) => b.focus - a.focus);
658
+
659
+ // Get top problematic letters
660
+ const problemLetters = letterScores.slice(0, 5).map(s => s.key);
661
+
662
+ // Categorize problem areas
663
+ const problemDigraphs = [];
664
+ const problemPatterns = [];
665
+
666
+ // Check for problematic digraphs
667
+ for (const [digraph, words] of Object.entries(WORD_CORPUS.digraphs)) {
668
+ if (digraph.split('').some(letter => problemLetters.includes(letter))) {
669
+ problemDigraphs.push({ pattern: digraph, words });
670
+ }
671
+ }
672
+
673
+ // Build adaptive drill
674
+ let drill = [];
675
+ let currentLength = 0;
676
+
677
+ // Mix different types of practice
678
+ while (currentLength < length) {
679
+ const random = Math.random();
680
+
681
+ if (random < 0.4 && problemDigraphs.length > 0) {
682
+ // 40% - Focus on problematic digraphs
683
+ const digraph = problemDigraphs[Math.floor(Math.random() * problemDigraphs.length)];
684
+ const word = digraph.words[Math.floor(Math.random() * digraph.words.length)];
685
+ drill.push(word);
686
+ currentLength += word.length + 1;
687
+ } else if (random < 0.7) {
688
+ // 30% - Words containing problem letters
689
+ const targetLetter = problemLetters[Math.floor(Math.random() * Math.min(3, problemLetters.length))];
690
+ const candidates = [
691
+ ...WORD_CORPUS.common,
692
+ ...Object.values(WORD_CORPUS.patterns).flat()
693
+ ].filter(w => w.includes(targetLetter));
694
+
695
+ if (candidates.length > 0) {
696
+ const word = candidates[Math.floor(Math.random() * candidates.length)];
697
+ drill.push(word);
698
+ currentLength += word.length + 1;
699
+ }
700
+ } else if (random < 0.85) {
701
+ // 15% - Common words for flow
702
+ const word = WORD_CORPUS.common[Math.floor(Math.random() * WORD_CORPUS.common.length)];
703
+ drill.push(word);
704
+ currentLength += word.length + 1;
705
+ } else {
706
+ // 15% - Generate a short sentence
707
+ if (currentLength + 20 < length) {
708
+ const sentence = generateSentence(problemLetters);
709
+ drill.push(sentence);
710
+ currentLength += sentence.length + 1;
711
+ }
712
+ }
713
+ }
714
+
715
+ // Format the drill nicely
716
+ const drillText = drill.join(' ').trim();
717
+
718
+ // Add a note about what we're focusing on
719
+ const focusNote = problemLetters.length > 0
720
+ ? `Focus areas: ${problemLetters.map(l => l.toUpperCase()).join(', ')} | `
721
+ : '';
722
+
723
+ return focusNote + drillText;
724
+ }
725
+
726
+ // Generate sentences with problem letters
727
+ function generateSentence(problemLetters) {
728
+ const template = SENTENCE_TEMPLATES[Math.floor(Math.random() * SENTENCE_TEMPLATES.length)];
729
+ let sentence = template;
730
+
731
+ // Replace placeholders with words containing problem letters when possible
732
+ for (const [type, words] of Object.entries(WORD_TYPES)) {
733
+ if (sentence.includes(`{${type}}`)) {
734
+ const candidates = words.filter(w =>
735
+ problemLetters.some(letter => w.includes(letter))
736
+ );
737
+ const wordList = candidates.length > 0 ? candidates : words;
738
+ const word = wordList[Math.floor(Math.random() * wordList.length)];
739
+ sentence = sentence.replace(`{${type}}`, word);
740
+ }
741
+ }
742
+
743
+ return sentence;
744
+ }
745
+
746
+ // Update the initial target text
747
+ function getInitialText() {
748
+ const introTexts = [
749
+ "Welcome to adaptive typing practice. Start with this sentence to build your profile.",
750
+ "Type this paragraph to help me understand your typing patterns and create personalized drills.",
751
+ "Every keystroke teaches me about your typing style. Let's begin with this warm-up text.",
752
+ "Practice makes perfect. Begin typing to discover your unique strengths and challenges.",
753
+ "Your personalized typing journey starts here. Type this text to establish your baseline."
754
+ ];
755
+
756
+ return introTexts[Math.floor(Math.random() * introTexts.length)];
757
+ }
758
+
759
  // Keyboard layout
760
  const KEY_ROWS = [
761
  ['q','w','e','r','t','y','u','i','o','p'],
 
881
  });
882
  }
883
 
884
+ // Enhanced drill generator
885
+ function generateDrill(posteriors, length = 80) {
886
  if (tracker.totalObservations < 20) {
887
+ // Start with common words for beginners
888
+ return "Type these common words: the quick brown fox jumps over the lazy dog. Practice makes perfect!";
889
  }
890
 
891
+ // Calculate focus scores for each letter
892
+ const letterScores = Object.entries(posteriors)
893
  .filter(([k, v]) => v.count > 0)
894
  .map(([k, v]) => ({
895
+ key: k,
896
  focus: v.mean * (v.sd + 0.1),
897
+ errorRate: v.mean,
898
+ uncertainty: v.sd
899
+ }))
900
+ .sort((a, b) => b.focus - a.focus);
901
+
902
+ // Get top problematic letters
903
+ const problemLetters = letterScores.slice(0, 5).map(s => s.key);
904
 
905
+ // Categorize problem areas
906
+ const problemDigraphs = [];
 
907
 
908
+ // Check for problematic digraphs
909
+ for (const [digraph, words] of Object.entries(WORD_CORPUS.digraphs)) {
910
+ if (digraph.split('').some(letter => problemLetters.includes(letter))) {
911
+ problemDigraphs.push({ pattern: digraph, words });
912
+ }
913
+ }
914
+
915
+ // Build adaptive drill
916
+ let drill = [];
917
+ let currentLength = 0;
918
 
919
+ // Mix different types of practice
920
+ while (currentLength < length) {
921
+ const random = Math.random();
922
+
923
+ if (random < 0.4 && problemDigraphs.length > 0) {
924
+ // 40% - Focus on problematic digraphs
925
+ const digraph = problemDigraphs[Math.floor(Math.random() * problemDigraphs.length)];
926
+ const word = digraph.words[Math.floor(Math.random() * digraph.words.length)];
927
+ drill.push(word);
928
+ currentLength += word.length + 1;
929
+ } else if (random < 0.7) {
930
+ // 30% - Words containing problem letters
931
+ const targetLetter = problemLetters[Math.floor(Math.random() * Math.min(3, problemLetters.length))];
932
+ const candidates = [
933
+ ...WORD_CORPUS.common,
934
+ ...Object.values(WORD_CORPUS.patterns).flat()
935
+ ].filter(w => w.includes(targetLetter));
936
 
937
+ if (candidates.length > 0) {
938
+ const word = candidates[Math.floor(Math.random() * candidates.length)];
939
+ drill.push(word);
940
+ currentLength += word.length + 1;
 
 
 
 
 
 
 
941
  }
942
+ } else if (random < 0.85) {
943
+ // 15% - Common words for flow
944
+ const word = WORD_CORPUS.common[Math.floor(Math.random() * WORD_CORPUS.common.length)];
945
+ drill.push(word);
946
+ currentLength += word.length + 1;
947
  } else {
948
+ // 15% - Generate a short sentence
949
+ if (currentLength + 20 < length) {
950
+ const sentence = generateSentence(problemLetters);
951
+ drill.push(sentence);
952
+ currentLength += sentence.length + 1;
953
+ }
954
  }
955
  }
956
+
957
+ // Format the drill nicely
958
+ const drillText = drill.join(' ').trim();
959
+
960
+ // Add a note about what we're focusing on
961
+ const focusNote = problemLetters.length > 0
962
+ ? `Focus: ${problemLetters.slice(0,3).map(l => l.toUpperCase()).join(', ')} | `
963
+ : '';
964
 
965
+ return focusNote + drillText;
966
  }
967
 
968
  function updateExplanation(posteriors){
 
1064
  updateHeatmap(post);
1065
  updateExplanation(post);
1066
 
1067
+ const drillText = generateDrill(post, 80);
1068
  drillDiv.textContent = drillText;
1069
 
1070
  updateStats(post);