-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtypes.ts
More file actions
141 lines (126 loc) · 4.04 KB
/
Copy pathtypes.ts
File metadata and controls
141 lines (126 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
* Shared type contract for the whole app.
*
* The physical keyboard is modeled once (layout-independent): each PhysicalKey
* has a position, an assigned finger/hand, and a home flag. A KeyboardLayout
* then maps each physical key id to the character(s) it produces. This is how
* real layout analyzers work — only the legends change between QWERTY / Dvorak /
* Colemak, never the physical positions or finger assignments.
*/
export type Hand = 'left' | 'right';
export type Finger =
| 'L-pinky'
| 'L-ring'
| 'L-middle'
| 'L-index'
| 'R-index'
| 'R-middle'
| 'R-ring'
| 'R-pinky'
| 'thumb';
export type RowName = 'number' | 'top' | 'home' | 'bottom' | 'space';
/** A physical key on a standard ANSI keyboard. Layout-independent. */
export interface PhysicalKey {
/** Stable id == the QWERTY base character at this position (e.g. 'a', ';', '4'). */
id: string;
/** x,y in key units. Origin top-left; x increases right, y increases down. */
x: number;
y: number;
/** Key width in units (most keys are 1; space is wide). */
width: number;
finger: Finger;
hand: Hand;
row: RowName;
/** True for the 8 home keys (A S D F J K L ;). */
isHome: boolean;
}
/** What a key types, unshifted and (optionally) shifted. */
export interface KeyLegend {
base: string;
shift?: string;
}
export type LayoutId =
| 'qwerty'
| 'qwertz'
| 'dvorak'
| 'colemak'
| 'colemak-dh'
| 'workman'
| 'norman';
export interface KeyboardLayout {
id: LayoutId;
name: string;
/** Maps physical key id -> the character(s) it produces in this layout. */
legends: Record<string, KeyLegend>;
}
/** A single resolved keystroke: which physical key, and whether shift is held. */
export interface KeyStroke {
char: string;
keyId: string;
needsShift: boolean;
}
/** Per-key accumulation used to render a term's heatmap. */
export interface KeyHeat {
keyId: string;
/** Number of times this key was pressed for the term. */
count: number;
/** Total effort (model units) this key contributed for the term. */
effort: number;
}
/** Transparent breakdown of *why* a term scored the way it did. */
export interface TermMetrics {
totalEffort: number;
estimatedMs: number;
wpm: number;
/** Number of analyzable characters (mappable on the layout). */
charCount: number;
/** Consecutive keys pressed by the same finger (the main speed killer). */
sameFingerBigrams: number;
/** Consecutive keys on opposite hands (fast). */
handAlternations: number;
/** handAlternations / (charCount - 1), 0..1. */
alternationRate: number;
/** Total finger travel from home, in key units. */
travelUnits: number;
/** Fraction of presses on each hand (0..1). */
leftHandLoad: number;
rightHandLoad: number;
}
export interface TermAnalysis {
/** The term exactly as entered. */
term: string;
/** What was actually analyzed (lowercased). */
normalized: string;
/** True if every character could be mapped on the chosen layout. */
supported: boolean;
unsupportedChars: string[];
strokes: KeyStroke[];
/** One entry per physical key that was used. */
heat: KeyHeat[];
metrics: TermMetrics;
}
export interface RankedTerm extends TermAnalysis {
/** 1 = best under the active sort (easiest to type by default). */
rank: number;
}
/**
* How ranked results are ordered:
* - 'ease': descending WPM — per-keystroke flow, independent of length (default).
* - 'time': ascending total estimated ms — fastest to finish, length counts.
*/
export type SortMode = 'ease' | 'time';
/** How the keyboard heatmap colors keys. */
export type HeatMode = 'frequency' | 'effort';
/**
* Props for the <Keyboard /> component (implemented by the keyboard-viz agent,
* consumed by the app shell). Documented here so both sides agree.
*/
export interface KeyboardProps {
layout: KeyboardLayout;
/** Heat data for the selected term; if omitted, renders a neutral keyboard. */
heat?: KeyHeat[];
/** Whether to color by press frequency or by effort. Default 'frequency'. */
mode?: HeatMode;
/** Optional accessible label. */
ariaLabel?: string;
}