Bionic Reading RU
unlistedby Влад Лямин
Bionic reading with proper Cyrillic support. Emphasizes the start of every word in reading and editing views.
Bionic Reading RU
Bionic reading for Obsidian that actually works with Cyrillic. It emphasizes the first part of every word so the eye has an anchor and the brain completes the rest.
Why another one
The two bionic plugins in the community registry silently do nothing on non-Latin text:
- one matches words with
[a-zA-ZÀ-ɏ], a Latin-only range; - the other splits words with
\Wand nouflag, where every Cyrillic character counts as a non-letter.
Here a word is \p{L} — a letter in any script. Cyrillic, Greek, Latin with diacritics and mixed tokens like n8n all work.
What it does
- Works in reading view and in editing view (Live Preview and source mode).
- The line under the cursor stays plain, so typing and selection are never disturbed.
- Skips code, math, frontmatter and URLs.
- Settings: separate toggles for reading and editing, fixation depth, emphasis weight.
- A "Toggle bionic reading" command you can bind to a hotkey.
Your notes are never modified. Reading view only changes rendered HTML; the editor only adds CodeMirror decorations. Nothing is written to disk.
Install
Not in the community registry yet.
With BRAT: add komzor5051/obsidian-bionic-reading-ru as a beta plugin.
Manually: download main.js, manifest.json and styles.css from Releases into <vault>/.obsidian/plugins/bionic-reading-ru/, then enable the plugin in Settings → Community plugins.
How it works
A single main.js, no build step: Obsidian exposes obsidian and @codemirror/* to plugins as external modules, so npm and esbuild are unnecessary.
- Core —
boldRanges(text, fixation)andboldLength(length, fixation). Pure functions that know nothing about the DOM or Obsidian. - Reading view —
decorateElement: a TreeWalker over text nodes, wrapping heads in<span class="bionic-ru">. - Editor — a
ViewPluginwithDecoration.mark. Decorations are built only overview.visibleRanges, so cost scales with the viewport rather than the note.
Decisions worth remembering
- The hyphen separates words; the apostrophe does not. Otherwise a compound like
AI-automationends up almost entirely bold instead of offering two separate anchors. - Cutting happens on code points, not UTF-16 units. A naive cut splits a surrogate pair in half and leaves a broken character.
- A
data-bionic-ruflag guards the container. On a second pass the tails of words would get emphasized too (bio|nic→bio|n|ic). Checking the parent's class is not enough — a tail lives in a bare text node next to the span, not inside it. Decoration.mark, never a replacing widget. The document is not altered by a single byte, so copy, search and cursor positions behave exactly as before.
Known limitations
- In Live Preview, blocks that Obsidian renders inside the editor (tables, callouts) are skipped on purpose, so their text is not processed twice. They are emphasized normally in reading view.
- The interface (sidebar, file names, search) and Dataview output are out of scope.
- CJK text is technically emphasized but the technique is not meaningful there.
Tests
node --test # 15 core tests: scripts, diacritics, surrogates, invariants
./test/run-smoke.sh # 12 DOM checks in headless Chrome (macOS path)
The smoke test covers what unit tests cannot: text integrity after node replacement, skipping code and math, and resilience to a repeated pass.
Performance
Measured in headless Chrome, the same engine Obsidian runs on. Median over 60 runs:
| Scenario | DOM nodes | Overhead |
|---|---|---|
| Editor viewport, 600 words | 1782 | +1.3 ms |
| A 7000-word note at once | 20793 | +16.4 ms |
The frame budget at 60 Hz is 16.67 ms. The second row is a synthetic worst case — one giant paragraph injected at once. In practice reading view renders block by block, around 0.2 ms per paragraph. Memory is roughly 460 KB per rendered screen, and the plugin does nothing at all while idle.
License
MIT
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.