Repository navigation
Name Reader
The app reads three pieces of text on screen: each draft card's item name, the hero name on the loading screen (turned into dark letters on white, 60 px tall, before the read: the raw colour crop read as nothing at 1920x1080), and the "N Re-Roll Remaining" caption. After 0.4.0 these are read by Windows OCR (Windows.Media.Ocr, part of Windows 10 and 11), not Tesseract. Nothing extra is installed and no window opens: the app starts one hidden PowerShell helper when it opens, warms it with one test picture, and sends it each text crop.
-
electron/nameReader.tsstartswinocr-helper.ps1(shipped next to the app) hidden. The log linereader.readygives the start time. If the helper exits it is started once more; if it exits again (or never starts) the status line says Name reader not running, cards that are not read show a grey?, the hero comes from the window or your pick, and the re-roll count uses the glyph shape alone. The app keeps running. - The text is matched to item and hero names exactly as before (
matchItemName,matchHeroNameat 0.85). -
Tooltips. Hovering a card makes the game draw a tooltip panel beside it, over a neighbour's name line. The panel's
text sits off centre in that line (a card's own name is always centred), so the app treats that line as covered: it is
not read and the card keeps the item it read before. A card that has never been seen uncovered shows a grey
?and gets its advice the moment it is read uncovered. A read that names the same item as another card is a tooltip title too, and both are read again. Log reasoncoveredoncard.name.unsure.
544 labelled name crops: the five demo frames, the live frames, the 10 OBS video truth stretches at 1280x720 and the stored session crops. 30 are covered by a tooltip (skipped by the rule above), 514 are uncovered.
| Engine | Wrong | Sure (of 514) | Cold start | Warm p50 | Warm p95 |
|---|---|---|---|---|---|
| Windows OCR | 0 | 98.2 % (9 unsure) | 981 ms | 6.8 ms | 20.3 ms |
| Tesseract 7 (old) | 0 | 98.1 % (10 unsure) | 1135 ms | 51.8 ms | 67.5 ms |
Per size (the five demo frames scaled; 14 labelled cards each; read time per card):
| Size | Windows OCR sure / wrong | Windows OCR p50 / p95 | Tesseract sure / wrong | Tesseract p50 / p95 |
|---|---|---|---|---|
| 1280x720 | 14 / 0 | 6.0 / 18.5 ms | 14 / 0 | 49.3 / 70.0 ms |
| 1920x1080 | 14 / 0 | 7.2 / 20.3 ms | 14 / 0 | 48.5 / 62.0 ms |
| 2560x1440 | 14 / 0 | 8.0 / 19.9 ms | 14 / 0 | 61.5 / 76.3 ms |
Cold start: Windows OCR is the helper's start to its first answer (PowerShell and the OCR engine); Tesseract is its
worker and model load to its first answer. Warm: 20 reads of each of 10 crops, the first two of each dropped. Measured
2026-10-10 on the development PC (Windows 11, run from WSL). The Tesseract numbers use the same crops through the old
reader (--engine tesseract, which needs npm i --no-save tesseract.js@7 for that run only).
All nine are 1280x720 frames from the OBS video truth set, and each gives no item for that frame (the card keeps waiting
for a frame that reads, and grey ? only if none does). In the video truth replay every one of these sets is still advised
with its right items.
| Frame | Card | Item | Reader text | Reason |
|---|---|---|---|---|
| s0#16 | middle | Toxic Bullets | "mage" | only part of the line read |
| s1#58 | right | Focus Lens | (nothing) | empty read |
| s2#10 | middle | Healing Tempo | "lealing Tet" | name cut off at both ends |
| s2#12 | middle | Healing Tempo | "Spilit 108 lealing Te" | tooltip text mixed into the line |
| s2#86 | right | Runed Gauntlets | (nothing) | empty read |
| s2#152 | right | Eternal Gift | "rnml G; '" | only part of the line read |
| s6#44 | right | Healing Nova | (nothing) | empty read |
| s7#2 | right | Bullet Resist Shredder | "let Resist Shred'*" | name cut off at both ends |
| s8#32 | right | Superior Duration | "erior DuW" | name cut off at both ends |
Seconds from a set becoming readable to its advice, per set, replayed frame by frame (4 frames per second, so steps of
0.25 s; each read is allowed to finish before the next frame, so this measures the logic, not the reader's speed).
- means the set was not readable for 1 s. The bar is 1.0 s on every stretch (ADVICE_BY in scripts/lib/videoTruth.ts,
was 1.5 s). Before = Tesseract with the old tooltip handling, after = Windows OCR with the covered rule.
| Stretch | Before (Tesseract) | After (Windows OCR) |
|---|---|---|
| s0 | -, -, 0.25 | -, -, 0.25 |
| s1 | 0, 0.25, 0.5, - | 0, 0.25, 0.75, - |
| s2 | 0.5, 0, 0.75, 0 | 0.5, -0.25, 0.75, 0 |
| s3 | 0, 0, -, 0 | 0, 0, -, 0 |
| s4 | 0.25, -, 0 | 1, -, 0 |
| s5 | 0.25, -2, 0.25 | 0.25, -2.25, 0.25 |
| s6 | -, 0.25, 0.5 | -, 0.25, 0.5 |
| s7 | 1, 0.25, 0 | 1, 0.25, 0 |
| s8 | 0, 1, 0.25, 0.25 | -0.25, 0.25, 0.25, 0.25 |
| s9 | -, 0, 0.25 | -, 0, 0.25 |
A negative value is advice that went up before the labelled readable start (the set was read on a frame the label
counts as still settling). s4's first set is 1 s now: its right card is under a tooltip on the first readable frames (s4#10 to 14),
so it waits for an uncovered frame instead of trusting a line the tooltip covers.
All four rules (right items, advice within the bar, no drop-out, no advice with no set) pass on every stretch.
The portable exe built with this change is 105.1 MB (105,086,526 bytes); the 0.4.0 release was 125.5 MB. The Tesseract engine and model are gone; the helper script adds 3.8 KB.
-
npm run names:compare -- --engine winocrscores recorded answers (scripts/fixtures/ocr-recorded/) anywhere;BRAWL_OCR=livereads every crop with the helper again (Windows, or WSL throughpowershell.exe),BRAWL_OCR=recordadds answers for new crops. -
npx tsx scripts/video-truth-report.tsprints the table above (about 3 min).