@staticcanvas/typeflow 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +637 -0
  3. package/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
  4. package/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
  5. package/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
  6. package/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
  7. package/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
  8. package/branding/dist/png/typeflow-logo-128x128.png +0 -0
  9. package/branding/dist/png/typeflow-logo-16x16.png +0 -0
  10. package/branding/dist/png/typeflow-logo-256x256.png +0 -0
  11. package/branding/dist/png/typeflow-logo-512x512.png +0 -0
  12. package/branding/dist/png/typeflow-logo-64x64.png +0 -0
  13. package/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
  14. package/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
  15. package/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
  16. package/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
  17. package/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
  18. package/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
  19. package/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
  20. package/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
  21. package/branding/gen-logo.ps1 +14 -0
  22. package/branding/typeflow-logo.svg +162 -0
  23. package/dist/typeflow/LICENSE +21 -0
  24. package/dist/typeflow/README.md +231 -0
  25. package/dist/typeflow/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
  26. package/dist/typeflow/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
  27. package/dist/typeflow/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
  28. package/dist/typeflow/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
  29. package/dist/typeflow/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
  30. package/dist/typeflow/branding/dist/png/typeflow-logo-128x128.png +0 -0
  31. package/dist/typeflow/branding/dist/png/typeflow-logo-16x16.png +0 -0
  32. package/dist/typeflow/branding/dist/png/typeflow-logo-256x256.png +0 -0
  33. package/dist/typeflow/branding/dist/png/typeflow-logo-512x512.png +0 -0
  34. package/dist/typeflow/branding/dist/png/typeflow-logo-64x64.png +0 -0
  35. package/dist/typeflow/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
  36. package/dist/typeflow/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
  37. package/dist/typeflow/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
  38. package/dist/typeflow/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
  39. package/dist/typeflow/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
  40. package/dist/typeflow/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
  41. package/dist/typeflow/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
  42. package/dist/typeflow/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
  43. package/dist/typeflow/branding/gen-logo.ps1 +14 -0
  44. package/dist/typeflow/branding/typeflow-logo.svg +162 -0
  45. package/dist/typeflow/dist/typeflow-caret.cjs +47 -0
  46. package/dist/typeflow/dist/typeflow-caret.cjs.map +1 -0
  47. package/dist/typeflow/dist/typeflow-caret.esm.js +47 -0
  48. package/dist/typeflow/dist/typeflow-caret.esm.js.map +1 -0
  49. package/dist/typeflow/dist/typeflow-caret.esm.min.js +2 -0
  50. package/dist/typeflow/dist/typeflow-caret.esm.min.js.map +1 -0
  51. package/dist/typeflow/dist/typeflow-caret.js +47 -0
  52. package/dist/typeflow/dist/typeflow-caret.js.map +1 -0
  53. package/dist/typeflow/dist/typeflow-caret.min.js +2 -0
  54. package/dist/typeflow/dist/typeflow-caret.min.js.map +1 -0
  55. package/dist/typeflow/dist/typeflow-caret.mjs +47 -0
  56. package/dist/typeflow/dist/typeflow-caret.mjs.map +1 -0
  57. package/dist/typeflow/dist/typeflow-debug.cjs +109 -0
  58. package/dist/typeflow/dist/typeflow-debug.cjs.map +1 -0
  59. package/dist/typeflow/dist/typeflow-debug.esm.js +109 -0
  60. package/dist/typeflow/dist/typeflow-debug.esm.js.map +1 -0
  61. package/dist/typeflow/dist/typeflow-debug.esm.min.js +2 -0
  62. package/dist/typeflow/dist/typeflow-debug.esm.min.js.map +1 -0
  63. package/dist/typeflow/dist/typeflow-debug.js +109 -0
  64. package/dist/typeflow/dist/typeflow-debug.js.map +1 -0
  65. package/dist/typeflow/dist/typeflow-debug.min.js +2 -0
  66. package/dist/typeflow/dist/typeflow-debug.min.js.map +1 -0
  67. package/dist/typeflow/dist/typeflow-debug.mjs +109 -0
  68. package/dist/typeflow/dist/typeflow-debug.mjs.map +1 -0
  69. package/dist/typeflow/dist/typeflow-extchars.cjs +66 -0
  70. package/dist/typeflow/dist/typeflow-extchars.cjs.map +1 -0
  71. package/dist/typeflow/dist/typeflow-extchars.esm.js +66 -0
  72. package/dist/typeflow/dist/typeflow-extchars.esm.js.map +1 -0
  73. package/dist/typeflow/dist/typeflow-extchars.esm.min.js +2 -0
  74. package/dist/typeflow/dist/typeflow-extchars.esm.min.js.map +1 -0
  75. package/dist/typeflow/dist/typeflow-extchars.js +66 -0
  76. package/dist/typeflow/dist/typeflow-extchars.js.map +1 -0
  77. package/dist/typeflow/dist/typeflow-extchars.min.js +2 -0
  78. package/dist/typeflow/dist/typeflow-extchars.min.js.map +1 -0
  79. package/dist/typeflow/dist/typeflow-extchars.mjs +66 -0
  80. package/dist/typeflow/dist/typeflow-extchars.mjs.map +1 -0
  81. package/dist/typeflow/dist/typeflow-keystroke.cjs +47 -0
  82. package/dist/typeflow/dist/typeflow-keystroke.cjs.map +1 -0
  83. package/dist/typeflow/dist/typeflow-keystroke.esm.js +47 -0
  84. package/dist/typeflow/dist/typeflow-keystroke.esm.js.map +1 -0
  85. package/dist/typeflow/dist/typeflow-keystroke.esm.min.js +2 -0
  86. package/dist/typeflow/dist/typeflow-keystroke.esm.min.js.map +1 -0
  87. package/dist/typeflow/dist/typeflow-keystroke.js +47 -0
  88. package/dist/typeflow/dist/typeflow-keystroke.js.map +1 -0
  89. package/dist/typeflow/dist/typeflow-keystroke.min.js +2 -0
  90. package/dist/typeflow/dist/typeflow-keystroke.min.js.map +1 -0
  91. package/dist/typeflow/dist/typeflow-keystroke.mjs +47 -0
  92. package/dist/typeflow/dist/typeflow-keystroke.mjs.map +1 -0
  93. package/dist/typeflow/dist/typeflow-metrics.cjs +76 -0
  94. package/dist/typeflow/dist/typeflow-metrics.cjs.map +1 -0
  95. package/dist/typeflow/dist/typeflow-metrics.esm.js +76 -0
  96. package/dist/typeflow/dist/typeflow-metrics.esm.js.map +1 -0
  97. package/dist/typeflow/dist/typeflow-metrics.esm.min.js +2 -0
  98. package/dist/typeflow/dist/typeflow-metrics.esm.min.js.map +1 -0
  99. package/dist/typeflow/dist/typeflow-metrics.js +76 -0
  100. package/dist/typeflow/dist/typeflow-metrics.js.map +1 -0
  101. package/dist/typeflow/dist/typeflow-metrics.min.js +2 -0
  102. package/dist/typeflow/dist/typeflow-metrics.min.js.map +1 -0
  103. package/dist/typeflow/dist/typeflow-metrics.mjs +76 -0
  104. package/dist/typeflow/dist/typeflow-metrics.mjs.map +1 -0
  105. package/dist/typeflow/dist/typeflow-parallel.cjs +3 -0
  106. package/dist/typeflow/dist/typeflow-parallel.cjs.map +1 -0
  107. package/dist/typeflow/dist/typeflow-parallel.esm.js +3 -0
  108. package/dist/typeflow/dist/typeflow-parallel.esm.js.map +1 -0
  109. package/dist/typeflow/dist/typeflow-parallel.esm.min.js +2 -0
  110. package/dist/typeflow/dist/typeflow-parallel.esm.min.js.map +1 -0
  111. package/dist/typeflow/dist/typeflow-parallel.js +3 -0
  112. package/dist/typeflow/dist/typeflow-parallel.js.map +1 -0
  113. package/dist/typeflow/dist/typeflow-parallel.min.js +2 -0
  114. package/dist/typeflow/dist/typeflow-parallel.min.js.map +1 -0
  115. package/dist/typeflow/dist/typeflow-parallel.mjs +3 -0
  116. package/dist/typeflow/dist/typeflow-parallel.mjs.map +1 -0
  117. package/dist/typeflow/dist/typeflow-webaudio.cjs +81 -0
  118. package/dist/typeflow/dist/typeflow-webaudio.cjs.map +1 -0
  119. package/dist/typeflow/dist/typeflow-webaudio.esm.js +81 -0
  120. package/dist/typeflow/dist/typeflow-webaudio.esm.js.map +1 -0
  121. package/dist/typeflow/dist/typeflow-webaudio.esm.min.js +2 -0
  122. package/dist/typeflow/dist/typeflow-webaudio.esm.min.js.map +1 -0
  123. package/dist/typeflow/dist/typeflow-webaudio.js +81 -0
  124. package/dist/typeflow/dist/typeflow-webaudio.js.map +1 -0
  125. package/dist/typeflow/dist/typeflow-webaudio.min.js +2 -0
  126. package/dist/typeflow/dist/typeflow-webaudio.min.js.map +1 -0
  127. package/dist/typeflow/dist/typeflow-webaudio.mjs +81 -0
  128. package/dist/typeflow/dist/typeflow-webaudio.mjs.map +1 -0
  129. package/dist/typeflow/dist/typeflow.cjs +277 -0
  130. package/dist/typeflow/dist/typeflow.cjs.map +1 -0
  131. package/dist/typeflow/dist/typeflow.esm.js +277 -0
  132. package/dist/typeflow/dist/typeflow.esm.js.map +1 -0
  133. package/dist/typeflow/dist/typeflow.esm.min.js +2 -0
  134. package/dist/typeflow/dist/typeflow.esm.min.js.map +1 -0
  135. package/dist/typeflow/dist/typeflow.js +277 -0
  136. package/dist/typeflow/dist/typeflow.js.map +1 -0
  137. package/dist/typeflow/dist/typeflow.min.js +2 -0
  138. package/dist/typeflow/dist/typeflow.min.js.map +1 -0
  139. package/dist/typeflow/dist/typeflow.mjs +277 -0
  140. package/dist/typeflow/dist/typeflow.mjs.map +1 -0
  141. package/dist/typeflow/jsr.jsonc +27 -0
  142. package/dist/typeflow/package.json +79 -0
  143. package/dist/typeflow/src/typeflow-audio-presets.js +137 -0
  144. package/dist/typeflow/src/typeflow-caret.d.ts +65 -0
  145. package/dist/typeflow/src/typeflow-caret.js +303 -0
  146. package/dist/typeflow/src/typeflow-debug.d.ts +34 -0
  147. package/dist/typeflow/src/typeflow-debug.js +223 -0
  148. package/dist/typeflow/src/typeflow-extchars.d.ts +28 -0
  149. package/dist/typeflow/src/typeflow-extchars.js +132 -0
  150. package/dist/typeflow/src/typeflow-keystroke.d.ts +28 -0
  151. package/dist/typeflow/src/typeflow-keystroke.js +220 -0
  152. package/dist/typeflow/src/typeflow-metrics.d.ts +38 -0
  153. package/dist/typeflow/src/typeflow-metrics.js +556 -0
  154. package/dist/typeflow/src/typeflow-parallel.d.ts +36 -0
  155. package/dist/typeflow/src/typeflow-parallel.js +157 -0
  156. package/dist/typeflow/src/typeflow-webaudio.d.ts +83 -0
  157. package/dist/typeflow/src/typeflow-webaudio.js +517 -0
  158. package/dist/typeflow/src/typeflow.d.ts +328 -0
  159. package/dist/typeflow/src/typeflow.js +2119 -0
  160. package/jsr.jsonc +27 -0
  161. package/package.json +133 -0
  162. package/src/typeflow-audio-presets.js +137 -0
  163. package/src/typeflow-caret.d.ts +65 -0
  164. package/src/typeflow-caret.js +303 -0
  165. package/src/typeflow-debug.d.ts +34 -0
  166. package/src/typeflow-debug.js +223 -0
  167. package/src/typeflow-extchars.d.ts +28 -0
  168. package/src/typeflow-extchars.js +132 -0
  169. package/src/typeflow-keystroke.d.ts +28 -0
  170. package/src/typeflow-keystroke.js +220 -0
  171. package/src/typeflow-metrics.d.ts +38 -0
  172. package/src/typeflow-metrics.js +556 -0
  173. package/src/typeflow-parallel.d.ts +36 -0
  174. package/src/typeflow-parallel.js +157 -0
  175. package/src/typeflow-webaudio.d.ts +83 -0
  176. package/src/typeflow-webaudio.js +517 -0
  177. package/src/typeflow.d.ts +328 -0
  178. package/src/typeflow.js +2119 -0
@@ -0,0 +1,47 @@
1
+ /*! typeflow-keystroke | MIT */
2
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TypeflowKeystroke={})}(this,function(e){"use strict";const t={"`":[0,0],1:[0,1],2:[0,2],3:[0,3],4:[0,4],5:[0,5],6:[0,6],7:[0,7],8:[0,8],9:[0,9],0:[0,10],"-":[0,11],"=":[0,12],q:[1,1.5],w:[1,2.5],e:[1,3.5],r:[1,4.5],t:[1,5.5],y:[1,6.5],u:[1,7.5],i:[1,8.5],o:[1,9.5],p:[1,10.5],"[":[1,11.5],"]":[1,12.5],a:[2,1.8],s:[2,2.8],d:[2,3.8],f:[2,4.8],g:[2,5.8],h:[2,6.8],j:[2,7.8],k:[2,8.8],l:[2,9.8],";":[2,10.8],"'":[2,11.8],z:[3,2.2],x:[3,3.2],c:[3,4.2],v:[3,5.2],b:[3,6.2],n:[3,7.2],m:[3,8.2],",":[3,9.2],".":[3,10.2],"/":[3,11.2]," ":[4,6]},o={a:["s","q","z","w"],b:["v","g","h","n"],c:["x","d","f","v"],d:["s","e","r","f","c","x"],e:["w","s","d","r"],f:["d","r","t","g","v","c"],g:["f","t","y","h","b","v"],h:["g","y","u","j","n","b"],i:["u","j","k","o"],j:["h","u","i","k","m","n"],k:["j","i","o","l","m"],l:["k","o","p",";"],m:["n","j","k"],n:["b","h","j","m"],o:["i","k","l","p"],p:["o","l","["],q:["1","2","w","a"],r:["e","d","f","t"],s:["a","w","e","d","x","z"],t:["r","f","g","y"],u:["y","h","j","i"],v:["c","f","g","b"],w:["q","a","s","e"],x:["z","s","d","c"],y:["t","g","h","u"],z:["a","s","x"]};function n(e,o){const n=t[String(e).toLowerCase()]||[2,5],s=t[String(o).toLowerCase()]||[2,5],a=s[0]-n[0],r=s[1]-n[1];return Math.sqrt(r*r+a*a)}class s{
3
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
4
+ * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.
5
+ * @param {string} prevChar - Previously typed character.
6
+ * @param {string} nextChar - Character about to be typed.
7
+ * @param {Object} [options={}] - Cadence calculation options.
8
+ * @returns {number} Calculated delay in milliseconds.
9
+ *
10
+ * -------------
11
+ *
12
+ * @Properties
13
+ * @param {string} prevChar - The last typed character.
14
+ * @param {string} nextChar - The next character to type.
15
+ * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.
16
+ * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.
17
+ * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.
18
+ *
19
+ * -------------
20
+ *
21
+ * @example
22
+ * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });
23
+ * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });
24
+ */
25
+ static getDelay(e,t,o={}){const s=o.baseSpeed||45,a=1+(o.fatigueIndex||0)*(o.fatigueRate||1e-4),r=n(e,t),i=1+Math.min(.6,.06*r);let p=0;"."===e||"!"===e||"?"===e?p=240:","===e||";"===e||":"===e?p=120:" "!==e&&"\n"!==e||(p=35);const u=.85+.3*Math.random();return Math.round((s*i*a+p)*u)}
26
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
27
+ * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.
28
+ * @param {string} text - Source text string to humanize.
29
+ * @param {Object} [options={}] - Typo and cadence simulation settings.
30
+ * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).
31
+ *
32
+ * -------------
33
+ *
34
+ * @Properties
35
+ * @param {string} text - The input text.
36
+ * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).
37
+ * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.
38
+ *
39
+ * -------------
40
+ *
41
+ * @example
42
+ * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {
43
+ * errorRate: 0.05,
44
+ * hesitationMs: 200,
45
+ * });
46
+ */static humanize(e,t={}){var n;const s=null!=(n=t.errorRate)?n:.04,a=[];for(let n=0;n<e.length;n++){const r=e[n],i=r.toLowerCase(),p=o[i];if(p&&p.length>0&&Math.random()<s&&" "!==r&&"\n"!==r){const e=p[Math.floor(Math.random()*p.length)],o=r!==i?e.toUpperCase():e;a.push({type:"type",char:o,isTypo:!0}),a.push({type:"pause",duration:t.hesitationMs||180}),a.push({type:"erase",count:1}),a.push({type:"type",char:r,isTypo:!1})}else a.push({type:"type",char:r,isTypo:!1})}return a}}"undefined"!=typeof window&&(window.TypeFlowKeystroke=s),e.TypeFlowKeystroke=s,e.calculateKeyDistance=n,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
47
+ //# sourceMappingURL=typeflow-keystroke.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeflow-keystroke.cjs","sources":["../../../src/typeflow-keystroke.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Keystroke - Human Cadence, Finger Distance & Typo Simulation Engine.\n * Models physical QWERTY coordinate finger travel, burstiness, thought pauses,\n * fatigue deceleration, and realistic typo injection with backspace auto-correction.\n *\n * @module @staticcanvas/typeflow/keystroke\n */\n\n// QWERTY keyboard physical coordinates (row, col)\nconst QWERTY_COORDS = {\n '`': [0, 0],\n 1: [0, 1],\n 2: [0, 2],\n 3: [0, 3],\n 4: [0, 4],\n 5: [0, 5],\n 6: [0, 6],\n 7: [0, 7],\n 8: [0, 8],\n 9: [0, 9],\n 0: [0, 10],\n '-': [0, 11],\n '=': [0, 12],\n q: [1, 1.5],\n w: [1, 2.5],\n e: [1, 3.5],\n r: [1, 4.5],\n t: [1, 5.5],\n y: [1, 6.5],\n u: [1, 7.5],\n i: [1, 8.5],\n o: [1, 9.5],\n p: [1, 10.5],\n '[': [1, 11.5],\n ']': [1, 12.5],\n a: [2, 1.8],\n s: [2, 2.8],\n d: [2, 3.8],\n f: [2, 4.8],\n g: [2, 5.8],\n h: [2, 6.8],\n j: [2, 7.8],\n k: [2, 8.8],\n l: [2, 9.8],\n ';': [2, 10.8],\n \"'\": [2, 11.8],\n z: [3, 2.2],\n x: [3, 3.2],\n c: [3, 4.2],\n v: [3, 5.2],\n b: [3, 6.2],\n n: [3, 7.2],\n m: [3, 8.2],\n ',': [3, 9.2],\n '.': [3, 10.2],\n '/': [3, 11.2],\n ' ': [4, 6.0],\n};\n\n// Adjacent key neighborhood for realistic typo generation\nconst QWERTY_NEIGHBORS = {\n a: ['s', 'q', 'z', 'w'],\n b: ['v', 'g', 'h', 'n'],\n c: ['x', 'd', 'f', 'v'],\n d: ['s', 'e', 'r', 'f', 'c', 'x'],\n e: ['w', 's', 'd', 'r'],\n f: ['d', 'r', 't', 'g', 'v', 'c'],\n g: ['f', 't', 'y', 'h', 'b', 'v'],\n h: ['g', 'y', 'u', 'j', 'n', 'b'],\n i: ['u', 'j', 'k', 'o'],\n j: ['h', 'u', 'i', 'k', 'm', 'n'],\n k: ['j', 'i', 'o', 'l', 'm'],\n l: ['k', 'o', 'p', ';'],\n m: ['n', 'j', 'k'],\n n: ['b', 'h', 'j', 'm'],\n o: ['i', 'k', 'l', 'p'],\n p: ['o', 'l', '['],\n q: ['1', '2', 'w', 'a'],\n r: ['e', 'd', 'f', 't'],\n s: ['a', 'w', 'e', 'd', 'x', 'z'],\n t: ['r', 'f', 'g', 'y'],\n u: ['y', 'h', 'j', 'i'],\n v: ['c', 'f', 'g', 'b'],\n w: ['q', 'a', 's', 'e'],\n x: ['z', 's', 'd', 'c'],\n y: ['t', 'g', 'h', 'u'],\n z: ['a', 's', 'x'],\n};\n\n/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Calculates Euclidean physical key distance on a standard QWERTY keyboard layout.\n * @param {string} keyA - Starting character or key.\n * @param {string} keyB - Target character or key.\n * @returns {number} Physical distance in key coordinate units (approx 1.0 to 12.0).\n *\n * -------------\n *\n * @Properties\n * @param {string} keyA - First key name or character.\n * @param {string} keyB - Second key name or character.\n *\n * -------------\n *\n * @example\n * const distAdjacent = calculateKeyDistance('e', 'r'); // ~1.0\n * const distFar = calculateKeyDistance('q', 'p'); // ~9.0\n */\nexport function calculateKeyDistance(keyA, keyB) {\n const a = QWERTY_COORDS[String(keyA).toLowerCase()] || [2, 5];\n const b = QWERTY_COORDS[String(keyB).toLowerCase()] || [2, 5];\n const dy = b[0] - a[0];\n const dx = b[1] - a[1];\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nexport class TypeFlowKeystroke {\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.\n * @param {string} prevChar - Previously typed character.\n * @param {string} nextChar - Character about to be typed.\n * @param {Object} [options={}] - Cadence calculation options.\n * @returns {number} Calculated delay in milliseconds.\n *\n * -------------\n *\n * @Properties\n * @param {string} prevChar - The last typed character.\n * @param {string} nextChar - The next character to type.\n * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.\n * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.\n * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.\n *\n * -------------\n *\n * @example\n * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });\n * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });\n */\n static getDelay(prevChar, nextChar, options = {}) {\n const base = options.baseSpeed || 45;\n const fatigue = 1 + (options.fatigueIndex || 0) * (options.fatigueRate || 0.0001);\n\n // 1. Distance multiplier (farther keys take slightly longer)\n const dist = calculateKeyDistance(prevChar, nextChar);\n const distFactor = 1 + Math.min(0.6, dist * 0.06);\n\n // 2. Natural Punctuation Hesitations\n let pause = 0;\n if (prevChar === '.' || prevChar === '!' || prevChar === '?') pause = 240;\n else if (prevChar === ',' || prevChar === ';' || prevChar === ':') pause = 120;\n else if (prevChar === ' ' || prevChar === '\\n') pause = 35;\n\n // 3. Random Gaussian jitter (±15%)\n const jitter = 0.85 + Math.random() * 0.3;\n\n return Math.round((base * distFactor * fatigue + pause) * jitter);\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.\n * @param {string} text - Source text string to humanize.\n * @param {Object} [options={}] - Typo and cadence simulation settings.\n * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).\n *\n * -------------\n *\n * @Properties\n * @param {string} text - The input text.\n * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).\n * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.\n *\n * -------------\n *\n * @example\n * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {\n * errorRate: 0.05,\n * hesitationMs: 200,\n * });\n */\n static humanize(text, options = {}) {\n const errorRate = options.errorRate ?? 0.04;\n const actions = [];\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const lower = char.toLowerCase();\n const neighbors = QWERTY_NEIGHBORS[lower];\n\n // Introduce typo if character has neighbors and probability hits\n if (\n neighbors &&\n neighbors.length > 0 &&\n Math.random() < errorRate &&\n char !== ' ' &&\n char !== '\\n'\n ) {\n const typoChar = neighbors[Math.floor(Math.random() * neighbors.length)];\n const isUpper = char !== lower;\n const insertedTypo = isUpper ? typoChar.toUpperCase() : typoChar;\n\n // 1. Type the typo\n actions.push({ type: 'type', char: insertedTypo, isTypo: true });\n // 2. Realize mistake hesitation\n actions.push({ type: 'pause', duration: options.hesitationMs || 180 });\n // 3. Backspace typo\n actions.push({ type: 'erase', count: 1 });\n // 4. Type correct character\n actions.push({ type: 'type', char, isTypo: false });\n } else {\n actions.push({ type: 'type', char, isTypo: false });\n }\n }\n\n return actions;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowKeystroke = TypeFlowKeystroke;\n}\n"],"names":["QWERTY_COORDS","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","QWERTY_NEIGHBORS","calculateKeyDistance","keyA","keyB","String","toLowerCase","dy","dx","Math","sqrt","TypeFlowKeystroke","getDelay","prevChar","nextChar","options","base","baseSpeed","fatigue","fatigueIndex","fatigueRate","dist","distFactor","min","pause","jitter","random","round","humanize","text","errorRate","_a","actions","length","char","lower","neighbors","typoChar","floor","insertedTypo","toUpperCase","push","type","isTypo","duration","hesitationMs","count","window"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /*! typeflow-keystroke | MIT */
2
+ const t={"`":[0,0],1:[0,1],2:[0,2],3:[0,3],4:[0,4],5:[0,5],6:[0,6],7:[0,7],8:[0,8],9:[0,9],0:[0,10],"-":[0,11],"=":[0,12],q:[1,1.5],w:[1,2.5],e:[1,3.5],r:[1,4.5],t:[1,5.5],y:[1,6.5],u:[1,7.5],i:[1,8.5],o:[1,9.5],p:[1,10.5],"[":[1,11.5],"]":[1,12.5],a:[2,1.8],s:[2,2.8],d:[2,3.8],f:[2,4.8],g:[2,5.8],h:[2,6.8],j:[2,7.8],k:[2,8.8],l:[2,9.8],";":[2,10.8],"'":[2,11.8],z:[3,2.2],x:[3,3.2],c:[3,4.2],v:[3,5.2],b:[3,6.2],n:[3,7.2],m:[3,8.2],",":[3,9.2],".":[3,10.2],"/":[3,11.2]," ":[4,6]},e={a:["s","q","z","w"],b:["v","g","h","n"],c:["x","d","f","v"],d:["s","e","r","f","c","x"],e:["w","s","d","r"],f:["d","r","t","g","v","c"],g:["f","t","y","h","b","v"],h:["g","y","u","j","n","b"],i:["u","j","k","o"],j:["h","u","i","k","m","n"],k:["j","i","o","l","m"],l:["k","o","p",";"],m:["n","j","k"],n:["b","h","j","m"],o:["i","k","l","p"],p:["o","l","["],q:["1","2","w","a"],r:["e","d","f","t"],s:["a","w","e","d","x","z"],t:["r","f","g","y"],u:["y","h","j","i"],v:["c","f","g","b"],w:["q","a","s","e"],x:["z","s","d","c"],y:["t","g","h","u"],z:["a","s","x"]};function o(e,o){const n=t[String(e).toLowerCase()]||[2,5],s=t[String(o).toLowerCase()]||[2,5],a=s[0]-n[0],r=s[1]-n[1];return Math.sqrt(r*r+a*a)}class n{
3
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
4
+ * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.
5
+ * @param {string} prevChar - Previously typed character.
6
+ * @param {string} nextChar - Character about to be typed.
7
+ * @param {Object} [options={}] - Cadence calculation options.
8
+ * @returns {number} Calculated delay in milliseconds.
9
+ *
10
+ * -------------
11
+ *
12
+ * @Properties
13
+ * @param {string} prevChar - The last typed character.
14
+ * @param {string} nextChar - The next character to type.
15
+ * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.
16
+ * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.
17
+ * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.
18
+ *
19
+ * -------------
20
+ *
21
+ * @example
22
+ * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });
23
+ * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });
24
+ */
25
+ static getDelay(t,e,n={}){const s=n.baseSpeed||45,a=1+(n.fatigueIndex||0)*(n.fatigueRate||1e-4),r=o(t,e),h=1+Math.min(.6,.06*r);let p=0;"."===t||"!"===t||"?"===t?p=240:","===t||";"===t||":"===t?p=120:" "!==t&&"\n"!==t||(p=35);const i=.85+.3*Math.random();return Math.round((s*h*a+p)*i)}
26
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
27
+ * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.
28
+ * @param {string} text - Source text string to humanize.
29
+ * @param {Object} [options={}] - Typo and cadence simulation settings.
30
+ * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).
31
+ *
32
+ * -------------
33
+ *
34
+ * @Properties
35
+ * @param {string} text - The input text.
36
+ * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).
37
+ * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.
38
+ *
39
+ * -------------
40
+ *
41
+ * @example
42
+ * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {
43
+ * errorRate: 0.05,
44
+ * hesitationMs: 200,
45
+ * });
46
+ */static humanize(t,o={}){var n;const s=null!=(n=o.errorRate)?n:.04,a=[];for(let n=0;n<t.length;n++){const r=t[n],h=r.toLowerCase(),p=e[h];if(p&&p.length>0&&Math.random()<s&&" "!==r&&"\n"!==r){const t=p[Math.floor(Math.random()*p.length)],e=r!==h?t.toUpperCase():t;a.push({type:"type",char:e,isTypo:!0}),a.push({type:"pause",duration:o.hesitationMs||180}),a.push({type:"erase",count:1}),a.push({type:"type",char:r,isTypo:!1})}else a.push({type:"type",char:r,isTypo:!1})}return a}}"undefined"!=typeof window&&(window.TypeFlowKeystroke=n);export{n as TypeFlowKeystroke,o as calculateKeyDistance};
47
+ //# sourceMappingURL=typeflow-keystroke.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeflow-keystroke.esm.js","sources":["../../../src/typeflow-keystroke.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Keystroke - Human Cadence, Finger Distance & Typo Simulation Engine.\n * Models physical QWERTY coordinate finger travel, burstiness, thought pauses,\n * fatigue deceleration, and realistic typo injection with backspace auto-correction.\n *\n * @module @staticcanvas/typeflow/keystroke\n */\n\n// QWERTY keyboard physical coordinates (row, col)\nconst QWERTY_COORDS = {\n '`': [0, 0],\n 1: [0, 1],\n 2: [0, 2],\n 3: [0, 3],\n 4: [0, 4],\n 5: [0, 5],\n 6: [0, 6],\n 7: [0, 7],\n 8: [0, 8],\n 9: [0, 9],\n 0: [0, 10],\n '-': [0, 11],\n '=': [0, 12],\n q: [1, 1.5],\n w: [1, 2.5],\n e: [1, 3.5],\n r: [1, 4.5],\n t: [1, 5.5],\n y: [1, 6.5],\n u: [1, 7.5],\n i: [1, 8.5],\n o: [1, 9.5],\n p: [1, 10.5],\n '[': [1, 11.5],\n ']': [1, 12.5],\n a: [2, 1.8],\n s: [2, 2.8],\n d: [2, 3.8],\n f: [2, 4.8],\n g: [2, 5.8],\n h: [2, 6.8],\n j: [2, 7.8],\n k: [2, 8.8],\n l: [2, 9.8],\n ';': [2, 10.8],\n \"'\": [2, 11.8],\n z: [3, 2.2],\n x: [3, 3.2],\n c: [3, 4.2],\n v: [3, 5.2],\n b: [3, 6.2],\n n: [3, 7.2],\n m: [3, 8.2],\n ',': [3, 9.2],\n '.': [3, 10.2],\n '/': [3, 11.2],\n ' ': [4, 6.0],\n};\n\n// Adjacent key neighborhood for realistic typo generation\nconst QWERTY_NEIGHBORS = {\n a: ['s', 'q', 'z', 'w'],\n b: ['v', 'g', 'h', 'n'],\n c: ['x', 'd', 'f', 'v'],\n d: ['s', 'e', 'r', 'f', 'c', 'x'],\n e: ['w', 's', 'd', 'r'],\n f: ['d', 'r', 't', 'g', 'v', 'c'],\n g: ['f', 't', 'y', 'h', 'b', 'v'],\n h: ['g', 'y', 'u', 'j', 'n', 'b'],\n i: ['u', 'j', 'k', 'o'],\n j: ['h', 'u', 'i', 'k', 'm', 'n'],\n k: ['j', 'i', 'o', 'l', 'm'],\n l: ['k', 'o', 'p', ';'],\n m: ['n', 'j', 'k'],\n n: ['b', 'h', 'j', 'm'],\n o: ['i', 'k', 'l', 'p'],\n p: ['o', 'l', '['],\n q: ['1', '2', 'w', 'a'],\n r: ['e', 'd', 'f', 't'],\n s: ['a', 'w', 'e', 'd', 'x', 'z'],\n t: ['r', 'f', 'g', 'y'],\n u: ['y', 'h', 'j', 'i'],\n v: ['c', 'f', 'g', 'b'],\n w: ['q', 'a', 's', 'e'],\n x: ['z', 's', 'd', 'c'],\n y: ['t', 'g', 'h', 'u'],\n z: ['a', 's', 'x'],\n};\n\n/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Calculates Euclidean physical key distance on a standard QWERTY keyboard layout.\n * @param {string} keyA - Starting character or key.\n * @param {string} keyB - Target character or key.\n * @returns {number} Physical distance in key coordinate units (approx 1.0 to 12.0).\n *\n * -------------\n *\n * @Properties\n * @param {string} keyA - First key name or character.\n * @param {string} keyB - Second key name or character.\n *\n * -------------\n *\n * @example\n * const distAdjacent = calculateKeyDistance('e', 'r'); // ~1.0\n * const distFar = calculateKeyDistance('q', 'p'); // ~9.0\n */\nexport function calculateKeyDistance(keyA, keyB) {\n const a = QWERTY_COORDS[String(keyA).toLowerCase()] || [2, 5];\n const b = QWERTY_COORDS[String(keyB).toLowerCase()] || [2, 5];\n const dy = b[0] - a[0];\n const dx = b[1] - a[1];\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nexport class TypeFlowKeystroke {\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.\n * @param {string} prevChar - Previously typed character.\n * @param {string} nextChar - Character about to be typed.\n * @param {Object} [options={}] - Cadence calculation options.\n * @returns {number} Calculated delay in milliseconds.\n *\n * -------------\n *\n * @Properties\n * @param {string} prevChar - The last typed character.\n * @param {string} nextChar - The next character to type.\n * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.\n * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.\n * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.\n *\n * -------------\n *\n * @example\n * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });\n * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });\n */\n static getDelay(prevChar, nextChar, options = {}) {\n const base = options.baseSpeed || 45;\n const fatigue = 1 + (options.fatigueIndex || 0) * (options.fatigueRate || 0.0001);\n\n // 1. Distance multiplier (farther keys take slightly longer)\n const dist = calculateKeyDistance(prevChar, nextChar);\n const distFactor = 1 + Math.min(0.6, dist * 0.06);\n\n // 2. Natural Punctuation Hesitations\n let pause = 0;\n if (prevChar === '.' || prevChar === '!' || prevChar === '?') pause = 240;\n else if (prevChar === ',' || prevChar === ';' || prevChar === ':') pause = 120;\n else if (prevChar === ' ' || prevChar === '\\n') pause = 35;\n\n // 3. Random Gaussian jitter (±15%)\n const jitter = 0.85 + Math.random() * 0.3;\n\n return Math.round((base * distFactor * fatigue + pause) * jitter);\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.\n * @param {string} text - Source text string to humanize.\n * @param {Object} [options={}] - Typo and cadence simulation settings.\n * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).\n *\n * -------------\n *\n * @Properties\n * @param {string} text - The input text.\n * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).\n * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.\n *\n * -------------\n *\n * @example\n * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {\n * errorRate: 0.05,\n * hesitationMs: 200,\n * });\n */\n static humanize(text, options = {}) {\n const errorRate = options.errorRate ?? 0.04;\n const actions = [];\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const lower = char.toLowerCase();\n const neighbors = QWERTY_NEIGHBORS[lower];\n\n // Introduce typo if character has neighbors and probability hits\n if (\n neighbors &&\n neighbors.length > 0 &&\n Math.random() < errorRate &&\n char !== ' ' &&\n char !== '\\n'\n ) {\n const typoChar = neighbors[Math.floor(Math.random() * neighbors.length)];\n const isUpper = char !== lower;\n const insertedTypo = isUpper ? typoChar.toUpperCase() : typoChar;\n\n // 1. Type the typo\n actions.push({ type: 'type', char: insertedTypo, isTypo: true });\n // 2. Realize mistake hesitation\n actions.push({ type: 'pause', duration: options.hesitationMs || 180 });\n // 3. Backspace typo\n actions.push({ type: 'erase', count: 1 });\n // 4. Type correct character\n actions.push({ type: 'type', char, isTypo: false });\n } else {\n actions.push({ type: 'type', char, isTypo: false });\n }\n }\n\n return actions;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowKeystroke = TypeFlowKeystroke;\n}\n"],"names":["QWERTY_COORDS","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","QWERTY_NEIGHBORS","calculateKeyDistance","keyA","keyB","String","toLowerCase","dy","dx","Math","sqrt","TypeFlowKeystroke","getDelay","prevChar","nextChar","options","base","baseSpeed","fatigue","fatigueIndex","fatigueRate","dist","distFactor","min","pause","jitter","random","round","humanize","text","_a","errorRate","actions","length","char","lower","neighbors","typoChar","floor","insertedTypo","toUpperCase","push","type","isTypo","duration","hesitationMs","count","window"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const t={"`":[0,0],1:[0,1],2:[0,2],3:[0,3],4:[0,4],5:[0,5],6:[0,6],7:[0,7],8:[0,8],9:[0,9],0:[0,10],"-":[0,11],"=":[0,12],q:[1,1.5],w:[1,2.5],e:[1,3.5],r:[1,4.5],t:[1,5.5],y:[1,6.5],u:[1,7.5],i:[1,8.5],o:[1,9.5],p:[1,10.5],"[":[1,11.5],"]":[1,12.5],a:[2,1.8],s:[2,2.8],d:[2,3.8],f:[2,4.8],g:[2,5.8],h:[2,6.8],j:[2,7.8],k:[2,8.8],l:[2,9.8],";":[2,10.8],"'":[2,11.8],z:[3,2.2],x:[3,3.2],c:[3,4.2],v:[3,5.2],b:[3,6.2],n:[3,7.2],m:[3,8.2],",":[3,9.2],".":[3,10.2],"/":[3,11.2]," ":[4,6]},e={a:["s","q","z","w"],b:["v","g","h","n"],c:["x","d","f","v"],d:["s","e","r","f","c","x"],e:["w","s","d","r"],f:["d","r","t","g","v","c"],g:["f","t","y","h","b","v"],h:["g","y","u","j","n","b"],i:["u","j","k","o"],j:["h","u","i","k","m","n"],k:["j","i","o","l","m"],l:["k","o","p",";"],m:["n","j","k"],n:["b","h","j","m"],o:["i","k","l","p"],p:["o","l","["],q:["1","2","w","a"],r:["e","d","f","t"],s:["a","w","e","d","x","z"],t:["r","f","g","y"],u:["y","h","j","i"],v:["c","f","g","b"],w:["q","a","s","e"],x:["z","s","d","c"],y:["t","g","h","u"],z:["a","s","x"]};function o(e,o){const n=t[String(e).toLowerCase()]||[2,5],s=t[String(o).toLowerCase()]||[2,5],a=s[0]-n[0],r=s[1]-n[1];return Math.sqrt(r*r+a*a)}class n{static getDelay(t,e,n={}){const s=n.baseSpeed||45,a=1+(n.fatigueIndex||0)*(n.fatigueRate||1e-4),r=o(t,e),h=1+Math.min(.6,.06*r);let p=0;"."===t||"!"===t||"?"===t?p=240:","===t||";"===t||":"===t?p=120:" "!==t&&"\n"!==t||(p=35);const i=.85+.3*Math.random();return Math.round((s*h*a+p)*i)}static humanize(t,o={}){var n;const s=null!=(n=o.errorRate)?n:.04,a=[];for(let n=0;n<t.length;n++){const r=t[n],h=r.toLowerCase(),p=e[h];if(p&&p.length>0&&Math.random()<s&&" "!==r&&"\n"!==r){const t=p[Math.floor(Math.random()*p.length)],e=r!==h?t.toUpperCase():t;a.push({type:"type",char:e,isTypo:!0}),a.push({type:"pause",duration:o.hesitationMs||180}),a.push({type:"erase",count:1}),a.push({type:"type",char:r,isTypo:!1})}else a.push({type:"type",char:r,isTypo:!1})}return a}}"undefined"!=typeof window&&(window.TypeFlowKeystroke=n);export{n as TypeFlowKeystroke,o as calculateKeyDistance};
2
+ //# sourceMappingURL=typeflow-keystroke.esm.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeflow-keystroke.esm.min.js","sources":["../../../src/typeflow-keystroke.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Keystroke - Human Cadence, Finger Distance & Typo Simulation Engine.\n * Models physical QWERTY coordinate finger travel, burstiness, thought pauses,\n * fatigue deceleration, and realistic typo injection with backspace auto-correction.\n *\n * @module @staticcanvas/typeflow/keystroke\n */\n\n// QWERTY keyboard physical coordinates (row, col)\nconst QWERTY_COORDS = {\n '`': [0, 0],\n 1: [0, 1],\n 2: [0, 2],\n 3: [0, 3],\n 4: [0, 4],\n 5: [0, 5],\n 6: [0, 6],\n 7: [0, 7],\n 8: [0, 8],\n 9: [0, 9],\n 0: [0, 10],\n '-': [0, 11],\n '=': [0, 12],\n q: [1, 1.5],\n w: [1, 2.5],\n e: [1, 3.5],\n r: [1, 4.5],\n t: [1, 5.5],\n y: [1, 6.5],\n u: [1, 7.5],\n i: [1, 8.5],\n o: [1, 9.5],\n p: [1, 10.5],\n '[': [1, 11.5],\n ']': [1, 12.5],\n a: [2, 1.8],\n s: [2, 2.8],\n d: [2, 3.8],\n f: [2, 4.8],\n g: [2, 5.8],\n h: [2, 6.8],\n j: [2, 7.8],\n k: [2, 8.8],\n l: [2, 9.8],\n ';': [2, 10.8],\n \"'\": [2, 11.8],\n z: [3, 2.2],\n x: [3, 3.2],\n c: [3, 4.2],\n v: [3, 5.2],\n b: [3, 6.2],\n n: [3, 7.2],\n m: [3, 8.2],\n ',': [3, 9.2],\n '.': [3, 10.2],\n '/': [3, 11.2],\n ' ': [4, 6.0],\n};\n\n// Adjacent key neighborhood for realistic typo generation\nconst QWERTY_NEIGHBORS = {\n a: ['s', 'q', 'z', 'w'],\n b: ['v', 'g', 'h', 'n'],\n c: ['x', 'd', 'f', 'v'],\n d: ['s', 'e', 'r', 'f', 'c', 'x'],\n e: ['w', 's', 'd', 'r'],\n f: ['d', 'r', 't', 'g', 'v', 'c'],\n g: ['f', 't', 'y', 'h', 'b', 'v'],\n h: ['g', 'y', 'u', 'j', 'n', 'b'],\n i: ['u', 'j', 'k', 'o'],\n j: ['h', 'u', 'i', 'k', 'm', 'n'],\n k: ['j', 'i', 'o', 'l', 'm'],\n l: ['k', 'o', 'p', ';'],\n m: ['n', 'j', 'k'],\n n: ['b', 'h', 'j', 'm'],\n o: ['i', 'k', 'l', 'p'],\n p: ['o', 'l', '['],\n q: ['1', '2', 'w', 'a'],\n r: ['e', 'd', 'f', 't'],\n s: ['a', 'w', 'e', 'd', 'x', 'z'],\n t: ['r', 'f', 'g', 'y'],\n u: ['y', 'h', 'j', 'i'],\n v: ['c', 'f', 'g', 'b'],\n w: ['q', 'a', 's', 'e'],\n x: ['z', 's', 'd', 'c'],\n y: ['t', 'g', 'h', 'u'],\n z: ['a', 's', 'x'],\n};\n\n/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Calculates Euclidean physical key distance on a standard QWERTY keyboard layout.\n * @param {string} keyA - Starting character or key.\n * @param {string} keyB - Target character or key.\n * @returns {number} Physical distance in key coordinate units (approx 1.0 to 12.0).\n *\n * -------------\n *\n * @Properties\n * @param {string} keyA - First key name or character.\n * @param {string} keyB - Second key name or character.\n *\n * -------------\n *\n * @example\n * const distAdjacent = calculateKeyDistance('e', 'r'); // ~1.0\n * const distFar = calculateKeyDistance('q', 'p'); // ~9.0\n */\nexport function calculateKeyDistance(keyA, keyB) {\n const a = QWERTY_COORDS[String(keyA).toLowerCase()] || [2, 5];\n const b = QWERTY_COORDS[String(keyB).toLowerCase()] || [2, 5];\n const dy = b[0] - a[0];\n const dx = b[1] - a[1];\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nexport class TypeFlowKeystroke {\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.\n * @param {string} prevChar - Previously typed character.\n * @param {string} nextChar - Character about to be typed.\n * @param {Object} [options={}] - Cadence calculation options.\n * @returns {number} Calculated delay in milliseconds.\n *\n * -------------\n *\n * @Properties\n * @param {string} prevChar - The last typed character.\n * @param {string} nextChar - The next character to type.\n * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.\n * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.\n * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.\n *\n * -------------\n *\n * @example\n * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });\n * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });\n */\n static getDelay(prevChar, nextChar, options = {}) {\n const base = options.baseSpeed || 45;\n const fatigue = 1 + (options.fatigueIndex || 0) * (options.fatigueRate || 0.0001);\n\n // 1. Distance multiplier (farther keys take slightly longer)\n const dist = calculateKeyDistance(prevChar, nextChar);\n const distFactor = 1 + Math.min(0.6, dist * 0.06);\n\n // 2. Natural Punctuation Hesitations\n let pause = 0;\n if (prevChar === '.' || prevChar === '!' || prevChar === '?') pause = 240;\n else if (prevChar === ',' || prevChar === ';' || prevChar === ':') pause = 120;\n else if (prevChar === ' ' || prevChar === '\\n') pause = 35;\n\n // 3. Random Gaussian jitter (±15%)\n const jitter = 0.85 + Math.random() * 0.3;\n\n return Math.round((base * distFactor * fatigue + pause) * jitter);\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.\n * @param {string} text - Source text string to humanize.\n * @param {Object} [options={}] - Typo and cadence simulation settings.\n * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).\n *\n * -------------\n *\n * @Properties\n * @param {string} text - The input text.\n * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).\n * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.\n *\n * -------------\n *\n * @example\n * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {\n * errorRate: 0.05,\n * hesitationMs: 200,\n * });\n */\n static humanize(text, options = {}) {\n const errorRate = options.errorRate ?? 0.04;\n const actions = [];\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const lower = char.toLowerCase();\n const neighbors = QWERTY_NEIGHBORS[lower];\n\n // Introduce typo if character has neighbors and probability hits\n if (\n neighbors &&\n neighbors.length > 0 &&\n Math.random() < errorRate &&\n char !== ' ' &&\n char !== '\\n'\n ) {\n const typoChar = neighbors[Math.floor(Math.random() * neighbors.length)];\n const isUpper = char !== lower;\n const insertedTypo = isUpper ? typoChar.toUpperCase() : typoChar;\n\n // 1. Type the typo\n actions.push({ type: 'type', char: insertedTypo, isTypo: true });\n // 2. Realize mistake hesitation\n actions.push({ type: 'pause', duration: options.hesitationMs || 180 });\n // 3. Backspace typo\n actions.push({ type: 'erase', count: 1 });\n // 4. Type correct character\n actions.push({ type: 'type', char, isTypo: false });\n } else {\n actions.push({ type: 'type', char, isTypo: false });\n }\n }\n\n return actions;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowKeystroke = TypeFlowKeystroke;\n}\n"],"names":["QWERTY_COORDS","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","QWERTY_NEIGHBORS","calculateKeyDistance","keyA","keyB","String","toLowerCase","dy","dx","Math","sqrt","TypeFlowKeystroke","getDelay","prevChar","nextChar","options","base","baseSpeed","fatigue","fatigueIndex","fatigueRate","dist","distFactor","min","pause","jitter","random","round","humanize","text","_a","errorRate","actions","length","char","lower","neighbors","typoChar","floor","insertedTypo","toUpperCase","push","type","isTypo","duration","hesitationMs","count","window"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /*! typeflow-keystroke | MIT */
2
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TypeflowKeystroke={})}(this,function(e){"use strict";const t={"`":[0,0],1:[0,1],2:[0,2],3:[0,3],4:[0,4],5:[0,5],6:[0,6],7:[0,7],8:[0,8],9:[0,9],0:[0,10],"-":[0,11],"=":[0,12],q:[1,1.5],w:[1,2.5],e:[1,3.5],r:[1,4.5],t:[1,5.5],y:[1,6.5],u:[1,7.5],i:[1,8.5],o:[1,9.5],p:[1,10.5],"[":[1,11.5],"]":[1,12.5],a:[2,1.8],s:[2,2.8],d:[2,3.8],f:[2,4.8],g:[2,5.8],h:[2,6.8],j:[2,7.8],k:[2,8.8],l:[2,9.8],";":[2,10.8],"'":[2,11.8],z:[3,2.2],x:[3,3.2],c:[3,4.2],v:[3,5.2],b:[3,6.2],n:[3,7.2],m:[3,8.2],",":[3,9.2],".":[3,10.2],"/":[3,11.2]," ":[4,6]},o={a:["s","q","z","w"],b:["v","g","h","n"],c:["x","d","f","v"],d:["s","e","r","f","c","x"],e:["w","s","d","r"],f:["d","r","t","g","v","c"],g:["f","t","y","h","b","v"],h:["g","y","u","j","n","b"],i:["u","j","k","o"],j:["h","u","i","k","m","n"],k:["j","i","o","l","m"],l:["k","o","p",";"],m:["n","j","k"],n:["b","h","j","m"],o:["i","k","l","p"],p:["o","l","["],q:["1","2","w","a"],r:["e","d","f","t"],s:["a","w","e","d","x","z"],t:["r","f","g","y"],u:["y","h","j","i"],v:["c","f","g","b"],w:["q","a","s","e"],x:["z","s","d","c"],y:["t","g","h","u"],z:["a","s","x"]};function n(e,o){const n=t[String(e).toLowerCase()]||[2,5],s=t[String(o).toLowerCase()]||[2,5],a=s[0]-n[0],r=s[1]-n[1];return Math.sqrt(r*r+a*a)}class s{
3
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
4
+ * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.
5
+ * @param {string} prevChar - Previously typed character.
6
+ * @param {string} nextChar - Character about to be typed.
7
+ * @param {Object} [options={}] - Cadence calculation options.
8
+ * @returns {number} Calculated delay in milliseconds.
9
+ *
10
+ * -------------
11
+ *
12
+ * @Properties
13
+ * @param {string} prevChar - The last typed character.
14
+ * @param {string} nextChar - The next character to type.
15
+ * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.
16
+ * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.
17
+ * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.
18
+ *
19
+ * -------------
20
+ *
21
+ * @example
22
+ * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });
23
+ * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });
24
+ */
25
+ static getDelay(e,t,o={}){const s=o.baseSpeed||45,a=1+(o.fatigueIndex||0)*(o.fatigueRate||1e-4),r=n(e,t),i=1+Math.min(.6,.06*r);let p=0;"."===e||"!"===e||"?"===e?p=240:","===e||";"===e||":"===e?p=120:" "!==e&&"\n"!==e||(p=35);const u=.85+.3*Math.random();return Math.round((s*i*a+p)*u)}
26
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
27
+ * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.
28
+ * @param {string} text - Source text string to humanize.
29
+ * @param {Object} [options={}] - Typo and cadence simulation settings.
30
+ * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).
31
+ *
32
+ * -------------
33
+ *
34
+ * @Properties
35
+ * @param {string} text - The input text.
36
+ * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).
37
+ * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.
38
+ *
39
+ * -------------
40
+ *
41
+ * @example
42
+ * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {
43
+ * errorRate: 0.05,
44
+ * hesitationMs: 200,
45
+ * });
46
+ */static humanize(e,t={}){var n;const s=null!=(n=t.errorRate)?n:.04,a=[];for(let n=0;n<e.length;n++){const r=e[n],i=r.toLowerCase(),p=o[i];if(p&&p.length>0&&Math.random()<s&&" "!==r&&"\n"!==r){const e=p[Math.floor(Math.random()*p.length)],o=r!==i?e.toUpperCase():e;a.push({type:"type",char:o,isTypo:!0}),a.push({type:"pause",duration:t.hesitationMs||180}),a.push({type:"erase",count:1}),a.push({type:"type",char:r,isTypo:!1})}else a.push({type:"type",char:r,isTypo:!1})}return a}}"undefined"!=typeof window&&(window.TypeFlowKeystroke=s),e.TypeFlowKeystroke=s,e.calculateKeyDistance=n,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
47
+ //# sourceMappingURL=typeflow-keystroke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeflow-keystroke.js","sources":["../../../src/typeflow-keystroke.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Keystroke - Human Cadence, Finger Distance & Typo Simulation Engine.\n * Models physical QWERTY coordinate finger travel, burstiness, thought pauses,\n * fatigue deceleration, and realistic typo injection with backspace auto-correction.\n *\n * @module @staticcanvas/typeflow/keystroke\n */\n\n// QWERTY keyboard physical coordinates (row, col)\nconst QWERTY_COORDS = {\n '`': [0, 0],\n 1: [0, 1],\n 2: [0, 2],\n 3: [0, 3],\n 4: [0, 4],\n 5: [0, 5],\n 6: [0, 6],\n 7: [0, 7],\n 8: [0, 8],\n 9: [0, 9],\n 0: [0, 10],\n '-': [0, 11],\n '=': [0, 12],\n q: [1, 1.5],\n w: [1, 2.5],\n e: [1, 3.5],\n r: [1, 4.5],\n t: [1, 5.5],\n y: [1, 6.5],\n u: [1, 7.5],\n i: [1, 8.5],\n o: [1, 9.5],\n p: [1, 10.5],\n '[': [1, 11.5],\n ']': [1, 12.5],\n a: [2, 1.8],\n s: [2, 2.8],\n d: [2, 3.8],\n f: [2, 4.8],\n g: [2, 5.8],\n h: [2, 6.8],\n j: [2, 7.8],\n k: [2, 8.8],\n l: [2, 9.8],\n ';': [2, 10.8],\n \"'\": [2, 11.8],\n z: [3, 2.2],\n x: [3, 3.2],\n c: [3, 4.2],\n v: [3, 5.2],\n b: [3, 6.2],\n n: [3, 7.2],\n m: [3, 8.2],\n ',': [3, 9.2],\n '.': [3, 10.2],\n '/': [3, 11.2],\n ' ': [4, 6.0],\n};\n\n// Adjacent key neighborhood for realistic typo generation\nconst QWERTY_NEIGHBORS = {\n a: ['s', 'q', 'z', 'w'],\n b: ['v', 'g', 'h', 'n'],\n c: ['x', 'd', 'f', 'v'],\n d: ['s', 'e', 'r', 'f', 'c', 'x'],\n e: ['w', 's', 'd', 'r'],\n f: ['d', 'r', 't', 'g', 'v', 'c'],\n g: ['f', 't', 'y', 'h', 'b', 'v'],\n h: ['g', 'y', 'u', 'j', 'n', 'b'],\n i: ['u', 'j', 'k', 'o'],\n j: ['h', 'u', 'i', 'k', 'm', 'n'],\n k: ['j', 'i', 'o', 'l', 'm'],\n l: ['k', 'o', 'p', ';'],\n m: ['n', 'j', 'k'],\n n: ['b', 'h', 'j', 'm'],\n o: ['i', 'k', 'l', 'p'],\n p: ['o', 'l', '['],\n q: ['1', '2', 'w', 'a'],\n r: ['e', 'd', 'f', 't'],\n s: ['a', 'w', 'e', 'd', 'x', 'z'],\n t: ['r', 'f', 'g', 'y'],\n u: ['y', 'h', 'j', 'i'],\n v: ['c', 'f', 'g', 'b'],\n w: ['q', 'a', 's', 'e'],\n x: ['z', 's', 'd', 'c'],\n y: ['t', 'g', 'h', 'u'],\n z: ['a', 's', 'x'],\n};\n\n/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Calculates Euclidean physical key distance on a standard QWERTY keyboard layout.\n * @param {string} keyA - Starting character or key.\n * @param {string} keyB - Target character or key.\n * @returns {number} Physical distance in key coordinate units (approx 1.0 to 12.0).\n *\n * -------------\n *\n * @Properties\n * @param {string} keyA - First key name or character.\n * @param {string} keyB - Second key name or character.\n *\n * -------------\n *\n * @example\n * const distAdjacent = calculateKeyDistance('e', 'r'); // ~1.0\n * const distFar = calculateKeyDistance('q', 'p'); // ~9.0\n */\nexport function calculateKeyDistance(keyA, keyB) {\n const a = QWERTY_COORDS[String(keyA).toLowerCase()] || [2, 5];\n const b = QWERTY_COORDS[String(keyB).toLowerCase()] || [2, 5];\n const dy = b[0] - a[0];\n const dx = b[1] - a[1];\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nexport class TypeFlowKeystroke {\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.\n * @param {string} prevChar - Previously typed character.\n * @param {string} nextChar - Character about to be typed.\n * @param {Object} [options={}] - Cadence calculation options.\n * @returns {number} Calculated delay in milliseconds.\n *\n * -------------\n *\n * @Properties\n * @param {string} prevChar - The last typed character.\n * @param {string} nextChar - The next character to type.\n * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.\n * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.\n * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.\n *\n * -------------\n *\n * @example\n * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });\n * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });\n */\n static getDelay(prevChar, nextChar, options = {}) {\n const base = options.baseSpeed || 45;\n const fatigue = 1 + (options.fatigueIndex || 0) * (options.fatigueRate || 0.0001);\n\n // 1. Distance multiplier (farther keys take slightly longer)\n const dist = calculateKeyDistance(prevChar, nextChar);\n const distFactor = 1 + Math.min(0.6, dist * 0.06);\n\n // 2. Natural Punctuation Hesitations\n let pause = 0;\n if (prevChar === '.' || prevChar === '!' || prevChar === '?') pause = 240;\n else if (prevChar === ',' || prevChar === ';' || prevChar === ':') pause = 120;\n else if (prevChar === ' ' || prevChar === '\\n') pause = 35;\n\n // 3. Random Gaussian jitter (±15%)\n const jitter = 0.85 + Math.random() * 0.3;\n\n return Math.round((base * distFactor * fatigue + pause) * jitter);\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.\n * @param {string} text - Source text string to humanize.\n * @param {Object} [options={}] - Typo and cadence simulation settings.\n * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).\n *\n * -------------\n *\n * @Properties\n * @param {string} text - The input text.\n * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).\n * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.\n *\n * -------------\n *\n * @example\n * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {\n * errorRate: 0.05,\n * hesitationMs: 200,\n * });\n */\n static humanize(text, options = {}) {\n const errorRate = options.errorRate ?? 0.04;\n const actions = [];\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const lower = char.toLowerCase();\n const neighbors = QWERTY_NEIGHBORS[lower];\n\n // Introduce typo if character has neighbors and probability hits\n if (\n neighbors &&\n neighbors.length > 0 &&\n Math.random() < errorRate &&\n char !== ' ' &&\n char !== '\\n'\n ) {\n const typoChar = neighbors[Math.floor(Math.random() * neighbors.length)];\n const isUpper = char !== lower;\n const insertedTypo = isUpper ? typoChar.toUpperCase() : typoChar;\n\n // 1. Type the typo\n actions.push({ type: 'type', char: insertedTypo, isTypo: true });\n // 2. Realize mistake hesitation\n actions.push({ type: 'pause', duration: options.hesitationMs || 180 });\n // 3. Backspace typo\n actions.push({ type: 'erase', count: 1 });\n // 4. Type correct character\n actions.push({ type: 'type', char, isTypo: false });\n } else {\n actions.push({ type: 'type', char, isTypo: false });\n }\n }\n\n return actions;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowKeystroke = TypeFlowKeystroke;\n}\n"],"names":["QWERTY_COORDS","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","QWERTY_NEIGHBORS","calculateKeyDistance","keyA","keyB","String","toLowerCase","dy","dx","Math","sqrt","TypeFlowKeystroke","getDelay","prevChar","nextChar","options","base","baseSpeed","fatigue","fatigueIndex","fatigueRate","dist","distFactor","min","pause","jitter","random","round","humanize","text","errorRate","_a","actions","length","char","lower","neighbors","typoChar","floor","insertedTypo","toUpperCase","push","type","isTypo","duration","hesitationMs","count","window"],"mappings":";wPASA,MAAMA,EAAgB,CACpB,IAAK,CAAC,EAAG,GACT,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,IACP,IAAK,CAAC,EAAG,IACT,IAAK,CAAC,EAAG,IACTC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,MACP,IAAK,CAAC,EAAG,MACT,IAAK,CAAC,EAAG,MACTC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACP,IAAK,CAAC,EAAG,MACT,IAAK,CAAC,EAAG,MACTC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACPC,EAAG,CAAC,EAAG,KACP,IAAK,CAAC,EAAG,KACT,IAAK,CAAC,EAAG,MACT,IAAK,CAAC,EAAG,MACT,IAAK,CAAC,EAAG,IAILC,EAAmB,CACvBhB,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBa,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBF,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBT,EAAG,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7BV,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBW,EAAG,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7BC,EAAG,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7BC,EAAG,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7BR,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBS,EAAG,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7BC,EAAG,CAAC,IAAK,IAAK,IAAK,IAAK,KACxBC,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBO,EAAG,CAAC,IAAK,IAAK,KACdD,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBhB,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBC,EAAG,CAAC,IAAK,IAAK,KACdT,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBG,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBQ,EAAG,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7BP,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBE,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBgB,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBrB,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBmB,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBf,EAAG,CAAC,IAAK,IAAK,IAAK,KACnBc,EAAG,CAAC,IAAK,IAAK,MAqBT,SAASQ,EAAqBC,EAAMC,GACzC,MAAMnB,EAAIX,EAAc+B,OAAOF,GAAMG,gBAAkB,CAAC,EAAG,GACrDR,EAAIxB,EAAc+B,OAAOD,GAAME,gBAAkB,CAAC,EAAG,GACrDC,EAAKT,EAAE,GAAKb,EAAE,GACduB,EAAKV,EAAE,GAAKb,EAAE,GACpB,OAAOwB,KAAKC,KAAKF,EAAKA,EAAKD,EAAKA,EAClC,CAEO,MAAMI;;;;;;;;;;;;;;;;;;;;;;;AAuBX,eAAOC,CAASC,EAAUC,EAAUC,EAAU,CAAA,GAC5C,MAAMC,EAAOD,EAAQE,WAAa,GAC5BC,EAAU,GAAKH,EAAQI,cAAgB,IAAMJ,EAAQK,aAAe,MAGpEC,EAAOnB,EAAqBW,EAAUC,GACtCQ,EAAa,EAAIb,KAAKc,IAAI,GAAY,IAAPF,GAGrC,IAAIG,EAAQ,EACK,MAAbX,GAAiC,MAAbA,GAAiC,MAAbA,EAAkBW,EAAQ,IAChD,MAAbX,GAAiC,MAAbA,GAAiC,MAAbA,EAAkBW,EAAQ,IACrD,MAAbX,GAAiC,OAAbA,IAAmBW,EAAQ,IAGxD,MAAMC,EAAS,IAAuB,GAAhBhB,KAAKiB,SAE3B,OAAOjB,KAAKkB,OAAOX,EAAOM,EAAaJ,EAAUM,GAASC,EAC5D;;;;;;;;;;;;;;;;;;;;;OAuBA,eAAOG,CAASC,EAAMd,EAAU,UAC9B,MAAMe,EAAY,OAAAC,EAAAhB,EAAQe,WAARC,EAAqB,IACjCC,EAAU,GAEhB,IAAA,IAASlD,EAAI,EAAGA,EAAI+C,EAAKI,OAAQnD,IAAK,CACpC,MAAMoD,EAAOL,EAAK/C,GACZqD,EAAQD,EAAK5B,cACb8B,EAAYnC,EAAiBkC,GAGnC,GACEC,GACAA,EAAUH,OAAS,GACnBxB,KAAKiB,SAAWI,GACP,MAATI,GACS,OAATA,EACA,CACA,MAAMG,EAAWD,EAAU3B,KAAK6B,MAAM7B,KAAKiB,SAAWU,EAAUH,SAE1DM,EADUL,IAASC,EACME,EAASG,cAAgBH,EAGxDL,EAAQS,KAAK,CAAEC,KAAM,OAAQR,KAAMK,EAAcI,QAAQ,IAEzDX,EAAQS,KAAK,CAAEC,KAAM,QAASE,SAAU7B,EAAQ8B,cAAgB,MAEhEb,EAAQS,KAAK,CAAEC,KAAM,QAASI,MAAO,IAErCd,EAAQS,KAAK,CAAEC,KAAM,OAAQR,OAAMS,QAAQ,GAC7C,MACEX,EAAQS,KAAK,CAAEC,KAAM,OAAQR,OAAMS,QAAQ,GAE/C,CAEA,OAAOX,CACT,EAGoB,oBAAXe,SACTA,OAAOpC,kBAAoBA"}
@@ -0,0 +1,2 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TypeflowKeystroke={})}(this,function(e){"use strict";const t={"`":[0,0],1:[0,1],2:[0,2],3:[0,3],4:[0,4],5:[0,5],6:[0,6],7:[0,7],8:[0,8],9:[0,9],0:[0,10],"-":[0,11],"=":[0,12],q:[1,1.5],w:[1,2.5],e:[1,3.5],r:[1,4.5],t:[1,5.5],y:[1,6.5],u:[1,7.5],i:[1,8.5],o:[1,9.5],p:[1,10.5],"[":[1,11.5],"]":[1,12.5],a:[2,1.8],s:[2,2.8],d:[2,3.8],f:[2,4.8],g:[2,5.8],h:[2,6.8],j:[2,7.8],k:[2,8.8],l:[2,9.8],";":[2,10.8],"'":[2,11.8],z:[3,2.2],x:[3,3.2],c:[3,4.2],v:[3,5.2],b:[3,6.2],n:[3,7.2],m:[3,8.2],",":[3,9.2],".":[3,10.2],"/":[3,11.2]," ":[4,6]},o={a:["s","q","z","w"],b:["v","g","h","n"],c:["x","d","f","v"],d:["s","e","r","f","c","x"],e:["w","s","d","r"],f:["d","r","t","g","v","c"],g:["f","t","y","h","b","v"],h:["g","y","u","j","n","b"],i:["u","j","k","o"],j:["h","u","i","k","m","n"],k:["j","i","o","l","m"],l:["k","o","p",";"],m:["n","j","k"],n:["b","h","j","m"],o:["i","k","l","p"],p:["o","l","["],q:["1","2","w","a"],r:["e","d","f","t"],s:["a","w","e","d","x","z"],t:["r","f","g","y"],u:["y","h","j","i"],v:["c","f","g","b"],w:["q","a","s","e"],x:["z","s","d","c"],y:["t","g","h","u"],z:["a","s","x"]};function n(e,o){const n=t[String(e).toLowerCase()]||[2,5],s=t[String(o).toLowerCase()]||[2,5],a=s[0]-n[0],r=s[1]-n[1];return Math.sqrt(r*r+a*a)}class s{static getDelay(e,t,o={}){const s=o.baseSpeed||45,a=1+(o.fatigueIndex||0)*(o.fatigueRate||1e-4),r=n(e,t),i=1+Math.min(.6,.06*r);let p=0;"."===e||"!"===e||"?"===e?p=240:","===e||";"===e||":"===e?p=120:" "!==e&&"\n"!==e||(p=35);const u=.85+.3*Math.random();return Math.round((s*i*a+p)*u)}static humanize(e,t={}){var n;const s=null!=(n=t.errorRate)?n:.04,a=[];for(let n=0;n<e.length;n++){const r=e[n],i=r.toLowerCase(),p=o[i];if(p&&p.length>0&&Math.random()<s&&" "!==r&&"\n"!==r){const e=p[Math.floor(Math.random()*p.length)],o=r!==i?e.toUpperCase():e;a.push({type:"type",char:o,isTypo:!0}),a.push({type:"pause",duration:t.hesitationMs||180}),a.push({type:"erase",count:1}),a.push({type:"type",char:r,isTypo:!1})}else a.push({type:"type",char:r,isTypo:!1})}return a}}"undefined"!=typeof window&&(window.TypeFlowKeystroke=s),e.TypeFlowKeystroke=s,e.calculateKeyDistance=n,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
2
+ //# sourceMappingURL=typeflow-keystroke.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeflow-keystroke.min.js","sources":["../../../src/typeflow-keystroke.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Keystroke - Human Cadence, Finger Distance & Typo Simulation Engine.\n * Models physical QWERTY coordinate finger travel, burstiness, thought pauses,\n * fatigue deceleration, and realistic typo injection with backspace auto-correction.\n *\n * @module @staticcanvas/typeflow/keystroke\n */\n\n// QWERTY keyboard physical coordinates (row, col)\nconst QWERTY_COORDS = {\n '`': [0, 0],\n 1: [0, 1],\n 2: [0, 2],\n 3: [0, 3],\n 4: [0, 4],\n 5: [0, 5],\n 6: [0, 6],\n 7: [0, 7],\n 8: [0, 8],\n 9: [0, 9],\n 0: [0, 10],\n '-': [0, 11],\n '=': [0, 12],\n q: [1, 1.5],\n w: [1, 2.5],\n e: [1, 3.5],\n r: [1, 4.5],\n t: [1, 5.5],\n y: [1, 6.5],\n u: [1, 7.5],\n i: [1, 8.5],\n o: [1, 9.5],\n p: [1, 10.5],\n '[': [1, 11.5],\n ']': [1, 12.5],\n a: [2, 1.8],\n s: [2, 2.8],\n d: [2, 3.8],\n f: [2, 4.8],\n g: [2, 5.8],\n h: [2, 6.8],\n j: [2, 7.8],\n k: [2, 8.8],\n l: [2, 9.8],\n ';': [2, 10.8],\n \"'\": [2, 11.8],\n z: [3, 2.2],\n x: [3, 3.2],\n c: [3, 4.2],\n v: [3, 5.2],\n b: [3, 6.2],\n n: [3, 7.2],\n m: [3, 8.2],\n ',': [3, 9.2],\n '.': [3, 10.2],\n '/': [3, 11.2],\n ' ': [4, 6.0],\n};\n\n// Adjacent key neighborhood for realistic typo generation\nconst QWERTY_NEIGHBORS = {\n a: ['s', 'q', 'z', 'w'],\n b: ['v', 'g', 'h', 'n'],\n c: ['x', 'd', 'f', 'v'],\n d: ['s', 'e', 'r', 'f', 'c', 'x'],\n e: ['w', 's', 'd', 'r'],\n f: ['d', 'r', 't', 'g', 'v', 'c'],\n g: ['f', 't', 'y', 'h', 'b', 'v'],\n h: ['g', 'y', 'u', 'j', 'n', 'b'],\n i: ['u', 'j', 'k', 'o'],\n j: ['h', 'u', 'i', 'k', 'm', 'n'],\n k: ['j', 'i', 'o', 'l', 'm'],\n l: ['k', 'o', 'p', ';'],\n m: ['n', 'j', 'k'],\n n: ['b', 'h', 'j', 'm'],\n o: ['i', 'k', 'l', 'p'],\n p: ['o', 'l', '['],\n q: ['1', '2', 'w', 'a'],\n r: ['e', 'd', 'f', 't'],\n s: ['a', 'w', 'e', 'd', 'x', 'z'],\n t: ['r', 'f', 'g', 'y'],\n u: ['y', 'h', 'j', 'i'],\n v: ['c', 'f', 'g', 'b'],\n w: ['q', 'a', 's', 'e'],\n x: ['z', 's', 'd', 'c'],\n y: ['t', 'g', 'h', 'u'],\n z: ['a', 's', 'x'],\n};\n\n/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Calculates Euclidean physical key distance on a standard QWERTY keyboard layout.\n * @param {string} keyA - Starting character or key.\n * @param {string} keyB - Target character or key.\n * @returns {number} Physical distance in key coordinate units (approx 1.0 to 12.0).\n *\n * -------------\n *\n * @Properties\n * @param {string} keyA - First key name or character.\n * @param {string} keyB - Second key name or character.\n *\n * -------------\n *\n * @example\n * const distAdjacent = calculateKeyDistance('e', 'r'); // ~1.0\n * const distFar = calculateKeyDistance('q', 'p'); // ~9.0\n */\nexport function calculateKeyDistance(keyA, keyB) {\n const a = QWERTY_COORDS[String(keyA).toLowerCase()] || [2, 5];\n const b = QWERTY_COORDS[String(keyB).toLowerCase()] || [2, 5];\n const dy = b[0] - a[0];\n const dx = b[1] - a[1];\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nexport class TypeFlowKeystroke {\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.\n * @param {string} prevChar - Previously typed character.\n * @param {string} nextChar - Character about to be typed.\n * @param {Object} [options={}] - Cadence calculation options.\n * @returns {number} Calculated delay in milliseconds.\n *\n * -------------\n *\n * @Properties\n * @param {string} prevChar - The last typed character.\n * @param {string} nextChar - The next character to type.\n * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.\n * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.\n * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.\n *\n * -------------\n *\n * @example\n * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });\n * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });\n */\n static getDelay(prevChar, nextChar, options = {}) {\n const base = options.baseSpeed || 45;\n const fatigue = 1 + (options.fatigueIndex || 0) * (options.fatigueRate || 0.0001);\n\n // 1. Distance multiplier (farther keys take slightly longer)\n const dist = calculateKeyDistance(prevChar, nextChar);\n const distFactor = 1 + Math.min(0.6, dist * 0.06);\n\n // 2. Natural Punctuation Hesitations\n let pause = 0;\n if (prevChar === '.' || prevChar === '!' || prevChar === '?') pause = 240;\n else if (prevChar === ',' || prevChar === ';' || prevChar === ':') pause = 120;\n else if (prevChar === ' ' || prevChar === '\\n') pause = 35;\n\n // 3. Random Gaussian jitter (±15%)\n const jitter = 0.85 + Math.random() * 0.3;\n\n return Math.round((base * distFactor * fatigue + pause) * jitter);\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.\n * @param {string} text - Source text string to humanize.\n * @param {Object} [options={}] - Typo and cadence simulation settings.\n * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).\n *\n * -------------\n *\n * @Properties\n * @param {string} text - The input text.\n * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).\n * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.\n *\n * -------------\n *\n * @example\n * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {\n * errorRate: 0.05,\n * hesitationMs: 200,\n * });\n */\n static humanize(text, options = {}) {\n const errorRate = options.errorRate ?? 0.04;\n const actions = [];\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const lower = char.toLowerCase();\n const neighbors = QWERTY_NEIGHBORS[lower];\n\n // Introduce typo if character has neighbors and probability hits\n if (\n neighbors &&\n neighbors.length > 0 &&\n Math.random() < errorRate &&\n char !== ' ' &&\n char !== '\\n'\n ) {\n const typoChar = neighbors[Math.floor(Math.random() * neighbors.length)];\n const isUpper = char !== lower;\n const insertedTypo = isUpper ? typoChar.toUpperCase() : typoChar;\n\n // 1. Type the typo\n actions.push({ type: 'type', char: insertedTypo, isTypo: true });\n // 2. Realize mistake hesitation\n actions.push({ type: 'pause', duration: options.hesitationMs || 180 });\n // 3. Backspace typo\n actions.push({ type: 'erase', count: 1 });\n // 4. Type correct character\n actions.push({ type: 'type', char, isTypo: false });\n } else {\n actions.push({ type: 'type', char, isTypo: false });\n }\n }\n\n return actions;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowKeystroke = TypeFlowKeystroke;\n}\n"],"names":["QWERTY_COORDS","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","QWERTY_NEIGHBORS","calculateKeyDistance","keyA","keyB","String","toLowerCase","dy","dx","Math","sqrt","TypeFlowKeystroke","getDelay","prevChar","nextChar","options","base","baseSpeed","fatigue","fatigueIndex","fatigueRate","dist","distFactor","min","pause","jitter","random","round","humanize","text","errorRate","_a","actions","length","char","lower","neighbors","typoChar","floor","insertedTypo","toUpperCase","push","type","isTypo","duration","hesitationMs","count","window"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /*! typeflow-keystroke | MIT */
2
+ const t={"`":[0,0],1:[0,1],2:[0,2],3:[0,3],4:[0,4],5:[0,5],6:[0,6],7:[0,7],8:[0,8],9:[0,9],0:[0,10],"-":[0,11],"=":[0,12],q:[1,1.5],w:[1,2.5],e:[1,3.5],r:[1,4.5],t:[1,5.5],y:[1,6.5],u:[1,7.5],i:[1,8.5],o:[1,9.5],p:[1,10.5],"[":[1,11.5],"]":[1,12.5],a:[2,1.8],s:[2,2.8],d:[2,3.8],f:[2,4.8],g:[2,5.8],h:[2,6.8],j:[2,7.8],k:[2,8.8],l:[2,9.8],";":[2,10.8],"'":[2,11.8],z:[3,2.2],x:[3,3.2],c:[3,4.2],v:[3,5.2],b:[3,6.2],n:[3,7.2],m:[3,8.2],",":[3,9.2],".":[3,10.2],"/":[3,11.2]," ":[4,6]},e={a:["s","q","z","w"],b:["v","g","h","n"],c:["x","d","f","v"],d:["s","e","r","f","c","x"],e:["w","s","d","r"],f:["d","r","t","g","v","c"],g:["f","t","y","h","b","v"],h:["g","y","u","j","n","b"],i:["u","j","k","o"],j:["h","u","i","k","m","n"],k:["j","i","o","l","m"],l:["k","o","p",";"],m:["n","j","k"],n:["b","h","j","m"],o:["i","k","l","p"],p:["o","l","["],q:["1","2","w","a"],r:["e","d","f","t"],s:["a","w","e","d","x","z"],t:["r","f","g","y"],u:["y","h","j","i"],v:["c","f","g","b"],w:["q","a","s","e"],x:["z","s","d","c"],y:["t","g","h","u"],z:["a","s","x"]};function o(e,o){const n=t[String(e).toLowerCase()]||[2,5],s=t[String(o).toLowerCase()]||[2,5],a=s[0]-n[0],r=s[1]-n[1];return Math.sqrt(r*r+a*a)}class n{
3
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
4
+ * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.
5
+ * @param {string} prevChar - Previously typed character.
6
+ * @param {string} nextChar - Character about to be typed.
7
+ * @param {Object} [options={}] - Cadence calculation options.
8
+ * @returns {number} Calculated delay in milliseconds.
9
+ *
10
+ * -------------
11
+ *
12
+ * @Properties
13
+ * @param {string} prevChar - The last typed character.
14
+ * @param {string} nextChar - The next character to type.
15
+ * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.
16
+ * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.
17
+ * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.
18
+ *
19
+ * -------------
20
+ *
21
+ * @example
22
+ * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });
23
+ * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });
24
+ */
25
+ static getDelay(t,e,n={}){const s=n.baseSpeed||45,a=1+(n.fatigueIndex||0)*(n.fatigueRate||1e-4),r=o(t,e),h=1+Math.min(.6,.06*r);let p=0;"."===t||"!"===t||"?"===t?p=240:","===t||";"===t||":"===t?p=120:" "!==t&&"\n"!==t||(p=35);const i=.85+.3*Math.random();return Math.round((s*h*a+p)*i)}
26
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
27
+ * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.
28
+ * @param {string} text - Source text string to humanize.
29
+ * @param {Object} [options={}] - Typo and cadence simulation settings.
30
+ * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).
31
+ *
32
+ * -------------
33
+ *
34
+ * @Properties
35
+ * @param {string} text - The input text.
36
+ * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).
37
+ * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.
38
+ *
39
+ * -------------
40
+ *
41
+ * @example
42
+ * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {
43
+ * errorRate: 0.05,
44
+ * hesitationMs: 200,
45
+ * });
46
+ */static humanize(t,o={}){var n;const s=null!=(n=o.errorRate)?n:.04,a=[];for(let n=0;n<t.length;n++){const r=t[n],h=r.toLowerCase(),p=e[h];if(p&&p.length>0&&Math.random()<s&&" "!==r&&"\n"!==r){const t=p[Math.floor(Math.random()*p.length)],e=r!==h?t.toUpperCase():t;a.push({type:"type",char:e,isTypo:!0}),a.push({type:"pause",duration:o.hesitationMs||180}),a.push({type:"erase",count:1}),a.push({type:"type",char:r,isTypo:!1})}else a.push({type:"type",char:r,isTypo:!1})}return a}}"undefined"!=typeof window&&(window.TypeFlowKeystroke=n);export{n as TypeFlowKeystroke,o as calculateKeyDistance};
47
+ //# sourceMappingURL=typeflow-keystroke.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeflow-keystroke.mjs","sources":["../../../src/typeflow-keystroke.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Keystroke - Human Cadence, Finger Distance & Typo Simulation Engine.\n * Models physical QWERTY coordinate finger travel, burstiness, thought pauses,\n * fatigue deceleration, and realistic typo injection with backspace auto-correction.\n *\n * @module @staticcanvas/typeflow/keystroke\n */\n\n// QWERTY keyboard physical coordinates (row, col)\nconst QWERTY_COORDS = {\n '`': [0, 0],\n 1: [0, 1],\n 2: [0, 2],\n 3: [0, 3],\n 4: [0, 4],\n 5: [0, 5],\n 6: [0, 6],\n 7: [0, 7],\n 8: [0, 8],\n 9: [0, 9],\n 0: [0, 10],\n '-': [0, 11],\n '=': [0, 12],\n q: [1, 1.5],\n w: [1, 2.5],\n e: [1, 3.5],\n r: [1, 4.5],\n t: [1, 5.5],\n y: [1, 6.5],\n u: [1, 7.5],\n i: [1, 8.5],\n o: [1, 9.5],\n p: [1, 10.5],\n '[': [1, 11.5],\n ']': [1, 12.5],\n a: [2, 1.8],\n s: [2, 2.8],\n d: [2, 3.8],\n f: [2, 4.8],\n g: [2, 5.8],\n h: [2, 6.8],\n j: [2, 7.8],\n k: [2, 8.8],\n l: [2, 9.8],\n ';': [2, 10.8],\n \"'\": [2, 11.8],\n z: [3, 2.2],\n x: [3, 3.2],\n c: [3, 4.2],\n v: [3, 5.2],\n b: [3, 6.2],\n n: [3, 7.2],\n m: [3, 8.2],\n ',': [3, 9.2],\n '.': [3, 10.2],\n '/': [3, 11.2],\n ' ': [4, 6.0],\n};\n\n// Adjacent key neighborhood for realistic typo generation\nconst QWERTY_NEIGHBORS = {\n a: ['s', 'q', 'z', 'w'],\n b: ['v', 'g', 'h', 'n'],\n c: ['x', 'd', 'f', 'v'],\n d: ['s', 'e', 'r', 'f', 'c', 'x'],\n e: ['w', 's', 'd', 'r'],\n f: ['d', 'r', 't', 'g', 'v', 'c'],\n g: ['f', 't', 'y', 'h', 'b', 'v'],\n h: ['g', 'y', 'u', 'j', 'n', 'b'],\n i: ['u', 'j', 'k', 'o'],\n j: ['h', 'u', 'i', 'k', 'm', 'n'],\n k: ['j', 'i', 'o', 'l', 'm'],\n l: ['k', 'o', 'p', ';'],\n m: ['n', 'j', 'k'],\n n: ['b', 'h', 'j', 'm'],\n o: ['i', 'k', 'l', 'p'],\n p: ['o', 'l', '['],\n q: ['1', '2', 'w', 'a'],\n r: ['e', 'd', 'f', 't'],\n s: ['a', 'w', 'e', 'd', 'x', 'z'],\n t: ['r', 'f', 'g', 'y'],\n u: ['y', 'h', 'j', 'i'],\n v: ['c', 'f', 'g', 'b'],\n w: ['q', 'a', 's', 'e'],\n x: ['z', 's', 'd', 'c'],\n y: ['t', 'g', 'h', 'u'],\n z: ['a', 's', 'x'],\n};\n\n/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Calculates Euclidean physical key distance on a standard QWERTY keyboard layout.\n * @param {string} keyA - Starting character or key.\n * @param {string} keyB - Target character or key.\n * @returns {number} Physical distance in key coordinate units (approx 1.0 to 12.0).\n *\n * -------------\n *\n * @Properties\n * @param {string} keyA - First key name or character.\n * @param {string} keyB - Second key name or character.\n *\n * -------------\n *\n * @example\n * const distAdjacent = calculateKeyDistance('e', 'r'); // ~1.0\n * const distFar = calculateKeyDistance('q', 'p'); // ~9.0\n */\nexport function calculateKeyDistance(keyA, keyB) {\n const a = QWERTY_COORDS[String(keyA).toLowerCase()] || [2, 5];\n const b = QWERTY_COORDS[String(keyB).toLowerCase()] || [2, 5];\n const dy = b[0] - a[0];\n const dx = b[1] - a[1];\n return Math.sqrt(dx * dx + dy * dy);\n}\n\nexport class TypeFlowKeystroke {\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Computes dynamic typing delay between two consecutive characters based on physical distance, fatigue, and punctuation.\n * @param {string} prevChar - Previously typed character.\n * @param {string} nextChar - Character about to be typed.\n * @param {Object} [options={}] - Cadence calculation options.\n * @returns {number} Calculated delay in milliseconds.\n *\n * -------------\n *\n * @Properties\n * @param {string} prevChar - The last typed character.\n * @param {string} nextChar - The next character to type.\n * @param {number} [options.baseSpeed=45] - Base typing speed in milliseconds per unit.\n * @param {number} [options.fatigueIndex=0] - Character index counter in active passage.\n * @param {number} [options.fatigueRate=0.0001] - Gradual deceleration coefficient per character.\n *\n * -------------\n *\n * @example\n * const delay = TypeFlowKeystroke.getDelay('a', 'b', { baseSpeed: 40 });\n * const pauseAfterPeriod = TypeFlowKeystroke.getDelay('.', 'T', { baseSpeed: 40 });\n */\n static getDelay(prevChar, nextChar, options = {}) {\n const base = options.baseSpeed || 45;\n const fatigue = 1 + (options.fatigueIndex || 0) * (options.fatigueRate || 0.0001);\n\n // 1. Distance multiplier (farther keys take slightly longer)\n const dist = calculateKeyDistance(prevChar, nextChar);\n const distFactor = 1 + Math.min(0.6, dist * 0.06);\n\n // 2. Natural Punctuation Hesitations\n let pause = 0;\n if (prevChar === '.' || prevChar === '!' || prevChar === '?') pause = 240;\n else if (prevChar === ',' || prevChar === ';' || prevChar === ':') pause = 120;\n else if (prevChar === ' ' || prevChar === '\\n') pause = 35;\n\n // 3. Random Gaussian jitter (±15%)\n const jitter = 0.85 + Math.random() * 0.3;\n\n return Math.round((base * distFactor * fatigue + pause) * jitter);\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Transforms plain text into a sequence of typing, hesitation pauses, adjacent-key typos, and backspace corrections.\n * @param {string} text - Source text string to humanize.\n * @param {Object} [options={}] - Typo and cadence simulation settings.\n * @returns {Array<Object>} List of step actions ({ type: 'type' | 'erase' | 'pause', char?, duration?, isTypo? }).\n *\n * -------------\n *\n * @Properties\n * @param {string} text - The input text.\n * @param {number} [options.errorRate=0.04] - Probability of introducing an adjacent-key typo (0.04 = 4%).\n * @param {number} [options.hesitationMs=180] - Pause duration in ms when a typo is made before backspacing.\n *\n * -------------\n *\n * @example\n * const actions = TypeFlowKeystroke.humanize('Fast, resilient, zero dependencies.', {\n * errorRate: 0.05,\n * hesitationMs: 200,\n * });\n */\n static humanize(text, options = {}) {\n const errorRate = options.errorRate ?? 0.04;\n const actions = [];\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const lower = char.toLowerCase();\n const neighbors = QWERTY_NEIGHBORS[lower];\n\n // Introduce typo if character has neighbors and probability hits\n if (\n neighbors &&\n neighbors.length > 0 &&\n Math.random() < errorRate &&\n char !== ' ' &&\n char !== '\\n'\n ) {\n const typoChar = neighbors[Math.floor(Math.random() * neighbors.length)];\n const isUpper = char !== lower;\n const insertedTypo = isUpper ? typoChar.toUpperCase() : typoChar;\n\n // 1. Type the typo\n actions.push({ type: 'type', char: insertedTypo, isTypo: true });\n // 2. Realize mistake hesitation\n actions.push({ type: 'pause', duration: options.hesitationMs || 180 });\n // 3. Backspace typo\n actions.push({ type: 'erase', count: 1 });\n // 4. Type correct character\n actions.push({ type: 'type', char, isTypo: false });\n } else {\n actions.push({ type: 'type', char, isTypo: false });\n }\n }\n\n return actions;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowKeystroke = TypeFlowKeystroke;\n}\n"],"names":["QWERTY_COORDS","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","QWERTY_NEIGHBORS","calculateKeyDistance","keyA","keyB","String","toLowerCase","dy","dx","Math","sqrt","TypeFlowKeystroke","getDelay","prevChar","nextChar","options","base","baseSpeed","fatigue","fatigueIndex","fatigueRate","dist","distFactor","min","pause","jitter","random","round","humanize","text","_a","errorRate","actions","length","char","lower","neighbors","typoChar","floor","insertedTypo","toUpperCase","push","type","isTypo","duration","hesitationMs","count","window"],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /*! typeflow-metrics | MIT */
2
+ !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).TypeflowMetrics={})}(this,function(t){"use strict";var n=Object.defineProperty,e=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,o=(t,e,i)=>e in t?n(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i;const a=class t{
3
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
4
+ * @description Constructs and initializes a TypeFlowMetrics tracker.
5
+ * @param {Object} [options={}] - Configuration options.
6
+ *
7
+ * -------------
8
+ *
9
+ * @Properties
10
+ * @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.
11
+ * @param {boolean} [options.detailed=false] - Whether to start with the expanded modal open.
12
+ * @param {boolean} [options.autoTrack=true] - Whether to observe global DOM mutations and animations.
13
+ * @param {number} [options.updateInterval=250] - Metric polling interval in milliseconds.
14
+ * @param {number} [options.zIndex=99999] - CSS z-index for floating badge.
15
+ *
16
+ * -------------
17
+ *
18
+ * @example
19
+ * const metrics = new TypeFlowMetrics({ position: 'bottom-right', detailed: true });
20
+ */
21
+ constructor(t={}){this.options=((t,n)=>{for(var a in n||(n={}))i.call(n,a)&&o(t,a,n[a]);if(e)for(var a of e(n))s.call(n,a)&&o(t,a,n[a]);return t})({position:"bottom-right",detailed:!1,autoTrack:!0,updateInterval:250,zIndex:99999},t),this.stats={fps:60,activeInstances:0,totalTyped:0,totalErased:0,renderLatencyMs:0,domMutations:0,interruptions:0,startTime:performance.now(),lastFrameTime:performance.now(),frameCount:0,history:[]},this.container=null,this.isExpanded=Boolean(this.options.detailed),this.rafId=null,this.intervalId=null,this.observer=null,"undefined"!=typeof window&&this.init()}
22
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
23
+ * @description Mounts the singleton floating HUD metrics badge into the active browser document.
24
+ * @param {Object} [options={}] - Custom configuration options.
25
+ * @returns {TypeFlowMetrics} The active singleton instance.
26
+ *
27
+ * -------------
28
+ *
29
+ * @Properties
30
+ * @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.
31
+ * @param {boolean} [options.detailed=false] - Whether to open expanded view initially.
32
+ *
33
+ * -------------
34
+ *
35
+ * @example
36
+ * TypeFlowMetrics.mount({ position: 'bottom-right' });
37
+ */static mount(n={}){return t.instance||(t.instance=new t(n)),t.instance}
38
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
39
+ * @description Unmounts the singleton floating HUD metrics badge and stops all listeners.
40
+ * @returns {void}
41
+ *
42
+ * -------------
43
+ *
44
+ * @example
45
+ * TypeFlowMetrics.unmount();
46
+ */static unmount(){t.instance&&(t.instance.destroy(),t.instance=null)}
47
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
48
+ * @description Returns a snapshot object of current performance metrics.
49
+ * @returns {Object | null} Metric snapshot data or null if not mounted.
50
+ *
51
+ * -------------
52
+ *
53
+ * @example
54
+ * const stats = TypeFlowMetrics.getStats();
55
+ * console.log('Active animations:', stats?.activeInstances);
56
+ */static getStats(){return t.instance?t.instance.getSnapshot():null}init(){this.createDom(),this.startFpsTracker(),this.startDomMutationObserver(),this.intervalId=setInterval(()=>{this.updateMetrics()},this.options.updateInterval)}createDom(){var t,n,e;if(this.container||"undefined"==typeof document)return;this.container=document.createElement("aside"),this.container.id="typeflow-metrics-hud",this.container.setAttribute("aria-label","TypeFlow Performance Metrics HUD"),this.container.setAttribute("role","region");const i={"bottom-right":"bottom: 16px; right: 16px;","bottom-left":"bottom: 16px; left: 16px;","top-right":"top: 16px; right: 16px;","top-left":"top: 16px; left: 16px;"},s=document.createElement("style");s.textContent=`\n #typeflow-metrics-hud {\n position: fixed;\n ${i[this.options.position]||i["bottom-right"]}\n z-index: ${this.options.zIndex};\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 12px;\n color: #f1f5f9;\n user-select: none;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n }\n #typeflow-metrics-hud * {\n box-sizing: border-box;\n }\n .tf-hud-pill {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: rgba(15, 23, 42, 0.85);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 9999px;\n box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.5), 0 0 15px rgba(255, 107, 43, 0.15);\n cursor: pointer;\n transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;\n }\n .tf-hud-pill:hover {\n transform: translateY(-2px);\n border-color: rgba(255, 107, 43, 0.5);\n box-shadow: 0 6px 24px -2px rgba(0, 0, 0, 0.6), 0 0 20px rgba(255, 107, 43, 0.3);\n }\n .tf-hud-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #10b981;\n box-shadow: 0 0 8px #10b981;\n transition: background 0.3s ease;\n }\n .tf-hud-dot.active {\n background: #ff6b2b;\n box-shadow: 0 0 10px #ff6b2b;\n animation: tf-hud-pulse 1.5s infinite;\n }\n @keyframes tf-hud-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.25); opacity: 0.7; }\n }\n .tf-hud-mono {\n font-family: 'JetBrains Mono', monospace;\n font-weight: 600;\n letter-spacing: -0.02em;\n }\n .tf-hud-label {\n color: #94a3b8;\n font-size: 11px;\n }\n .tf-hud-modal {\n display: none;\n width: 290px;\n background: rgba(15, 23, 42, 0.94);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 12px;\n box-shadow: 0 20px 40px -4px rgba(0, 0, 0, 0.6), 0 0 25px rgba(255, 107, 43, 0.15);\n padding: 14px;\n margin-top: 8px;\n animation: tf-hud-fade-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n @keyframes tf-hud-fade-in {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .tf-hud-modal.open {\n display: block;\n }\n .tf-hud-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: 10px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n margin-bottom: 10px;\n }\n .tf-hud-title {\n font-family: 'Lexend', sans-serif;\n font-weight: 600;\n font-size: 13px;\n background: linear-gradient(135deg, #ff6b2b, #38bdf8);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n .tf-hud-close {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 14px;\n line-height: 1;\n }\n .tf-hud-close:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n }\n .tf-hud-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n margin-bottom: 10px;\n }\n .tf-hud-card {\n background: rgba(30, 41, 59, 0.6);\n border: 1px solid rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n padding: 8px 10px;\n }\n .tf-hud-card-label {\n font-size: 10px;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 2px;\n }\n .tf-hud-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 14px;\n font-weight: 600;\n color: #e2e8f0;\n }\n .tf-hud-accent {\n color: #ff6b2b;\n }\n .tf-hud-cyan {\n color: #38bdf8;\n }\n .tf-hud-green {\n color: #10b981;\n }\n .tf-hud-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-top: 8px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n font-size: 10px;\n color: #64748b;\n }\n .tf-hud-btn {\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.1);\n color: #cbd5e1;\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 10px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .tf-hud-btn:hover {\n background: rgba(255, 107, 43, 0.2);\n border-color: rgba(255, 107, 43, 0.4);\n color: #ff6b2b;\n }\n `;const o=document.createElement("div");o.className="tf-hud-pill",o.setAttribute("role","button"),o.setAttribute("tabindex","0"),o.innerHTML='\n <span class="tf-hud-dot" id="tf-hud-dot"></span>\n <span class="tf-hud-mono" id="tf-hud-fps">60 FPS</span>\n <span class="tf-hud-label">•</span>\n <span class="tf-hud-mono tf-hud-accent" id="tf-hud-active">0 Active</span>\n ';const a=document.createElement("div");a.className="tf-hud-modal "+(this.isExpanded?"open":""),a.id="tf-hud-modal",a.innerHTML='\n <div class="tf-hud-header">\n <span class="tf-hud-title">TypeFlow Metrics</span>\n <button class="tf-hud-close" id="tf-hud-close" aria-label="Close Metrics Window">✕</button>\n </div>\n <div class="tf-hud-grid">\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Frame Rate</div>\n <div class="tf-hud-card-val tf-hud-green" id="tf-hud-m-fps">60.0 FPS</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Active Anim</div>\n <div class="tf-hud-card-val tf-hud-accent" id="tf-hud-m-active">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Typed Units</div>\n <div class="tf-hud-card-val tf-hud-cyan" id="tf-hud-m-typed">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Erased Units</div>\n <div class="tf-hud-card-val" id="tf-hud-m-erased">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">DOM Mut.</div>\n <div class="tf-hud-card-val" id="tf-hud-m-mut">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Heap Memory</div>\n <div class="tf-hud-card-val tf-hud-mono" id="tf-hud-m-mem">-- MB</div>\n </div>\n </div>\n <div class="tf-hud-footer">\n <span id="tf-hud-uptime">Uptime: 0s</span>\n <div style="display:flex;gap:4px;">\n <button class="tf-hud-btn" id="tf-hud-copy">Copy JSON</button>\n <button class="tf-hud-btn" id="tf-hud-reset">Reset</button>\n </div>\n </div>\n ',this.container.appendChild(s),this.container.appendChild(o),this.container.appendChild(a),document.body.appendChild(this.container),o.addEventListener("click",()=>this.toggleModal()),o.addEventListener("keydown",t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.toggleModal())}),null==(t=a.querySelector("#tf-hud-close"))||t.addEventListener("click",()=>this.toggleModal(!1)),null==(n=a.querySelector("#tf-hud-reset"))||n.addEventListener("click",()=>this.resetStats()),null==(e=a.querySelector("#tf-hud-copy"))||e.addEventListener("click",()=>this.copyStats())}
57
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
58
+ * @description Toggles or sets the visibility of the expanded metrics window modal.
59
+ * @param {boolean} [forceState] - Optional explicit state boolean.
60
+ * @returns {void}
61
+ *
62
+ * -------------
63
+ *
64
+ * @example
65
+ * hud.toggleModal(true); // Open
66
+ * hud.toggleModal(false); // Close
67
+ */toggleModal(t){var n;this.isExpanded=void 0!==t?t:!this.isExpanded;const e=null==(n=this.container)?void 0:n.querySelector("#tf-hud-modal");e&&e.classList.toggle("open",this.isExpanded)}startFpsTracker(){let t=performance.now(),n=0;const e=i=>{n++,i>=t+1e3&&(this.stats.fps=Math.round(1e3*n/(i-t)),n=0,t=i),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}startDomMutationObserver(){"undefined"!=typeof MutationObserver&&"undefined"!=typeof document&&(this.observer=new MutationObserver(t=>{var n,e;let i=0;for(const s of t)s.target===this.container||(null==(n=this.container)?void 0:n.contains(s.target))||1===s.target.nodeType&&(null==(e=s.target.classList)?void 0:e.contains("tf-cursor"))||i++;this.stats.domMutations+=i}),this.observer.observe(document.body,{childList:!0,subtree:!0,characterData:!0}))}recordTyped(t=1){this.stats.totalTyped+=t}recordErased(t=1){this.stats.totalErased+=t}recordInterruption(){this.stats.interruptions+=1}updateMetrics(){var t,n;if(!this.container)return;"undefined"!=typeof window&&(null==(t=window.TypeFlow)?void 0:t.active)&&(this.stats.activeInstances=window.TypeFlow.active.size);const e=this.container.querySelector("#tf-hud-dot"),i=this.container.querySelector("#tf-hud-fps"),s=this.container.querySelector("#tf-hud-active");if(e&&e.classList.toggle("active",this.stats.activeInstances>0),i&&(i.textContent=`${this.stats.fps} FPS`),s&&(s.textContent=`${this.stats.activeInstances} Active`),this.isExpanded){const t=this.container.querySelector("#tf-hud-m-fps"),e=this.container.querySelector("#tf-hud-m-active"),i=this.container.querySelector("#tf-hud-m-typed"),s=this.container.querySelector("#tf-hud-m-erased"),o=this.container.querySelector("#tf-hud-m-mut"),a=this.container.querySelector("#tf-hud-m-mem"),r=this.container.querySelector("#tf-hud-uptime");if(t&&(t.textContent=`${this.stats.fps}.0 FPS`),e&&(e.textContent=`${this.stats.activeInstances}`),i&&(i.textContent=this.stats.totalTyped.toLocaleString()),s&&(s.textContent=this.stats.totalErased.toLocaleString()),o&&(o.textContent=this.stats.domMutations.toLocaleString()),a)if(null==(n=performance.memory)?void 0:n.usedJSHeapSize){const t=(performance.memory.usedJSHeapSize/1048576).toFixed(1);a.textContent=`${t} MB`}else a.textContent="Native";if(r){const t=Math.floor((performance.now()-this.stats.startTime)/1e3);r.textContent=`Uptime: ${t}s`}}}resetStats(){this.stats.totalTyped=0,this.stats.totalErased=0,this.stats.domMutations=0,this.stats.interruptions=0,this.stats.startTime=performance.now(),this.updateMetrics()}copyStats(){var t,n;const e=JSON.stringify(this.getSnapshot(),null,2);if(null==(t=navigator.clipboard)?void 0:t.writeText){navigator.clipboard.writeText(e);const t=null==(n=this.container)?void 0:n.querySelector("#tf-hud-copy");if(t){const n=t.textContent;t.textContent="Copied!",setTimeout(()=>{t.textContent=n},1500)}}}
68
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
69
+ * @description Returns a snapshot object of lifetime metrics.
70
+ * @returns {Object} Metric data snapshot.
71
+ */getSnapshot(){return{timestamp:(new Date).toISOString(),fps:this.stats.fps,activeInstances:this.stats.activeInstances,totalTyped:this.stats.totalTyped,totalErased:this.stats.totalErased,domMutations:this.stats.domMutations,interruptions:this.stats.interruptions,uptimeSeconds:Math.floor((performance.now()-this.stats.startTime)/1e3)}}
72
+ /** * * * * * * * * * * * * * * * * * * * * * * * * * * **
73
+ * @description Cleans up observers, timers, and removes the HUD from the DOM.
74
+ * @returns {void}
75
+ */destroy(){var t;this.rafId&&cancelAnimationFrame(this.rafId),this.intervalId&&clearInterval(this.intervalId),this.observer&&this.observer.disconnect(),(null==(t=this.container)?void 0:t.parentNode)&&this.container.parentNode.removeChild(this.container),this.container=null}};var r;o(a,"symbol"!=typeof(r="instance")?r+"":r,null);let d=a;"undefined"!=typeof window&&(window.TypeFlowMetrics=d),t.TypeFlowMetrics=d,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
76
+ //# sourceMappingURL=typeflow-metrics.cjs.map