yunmin363 downloadsCount with traditional five-stroke Zheng tallies inline in Obsidian and resume them later.
A native-feeling 正 tally counter for Obsidian. Count stroke by stroke, keep it inline, and resume anytime.

Press Alt+Z, tap Space to count, Enter to commit. The tally renders as a
real inline 正 built from canonical stroke vectors, and it stays that way:
committed tallies remain vector chips you can click to resume.
Counting with 正 tallies in Markdown usually means typing characters by hand and losing count halfway. Zheng Tally turns it into a tight loop: start anywhere in a note, watch each stroke appear, commit a portable plain-text tally, and pick it back up later without retyping. The editor shows vectors; the file stays readable text.
Alt+Z drops an inline counter at the cursor.Space adds one canonical stroke (一 → … → 正), grouped in fives.Enter writes 正正正·3<!--zt:18--> — visible text plus a count marker.Alt+Z) to resume from 18. Esc never writes.正 vectors at every step — never a substituted characterFrom a release:
main.js and manifest.json from
Releases.<vault>/.obsidian/plugins/zheng-tally/.From source:
git clone https://github.com/yunmin311/zheng-tally-obsidian.git
cd zheng-tally-obsidian
npm install
npm run build
Copy dist/main.js, manifest.json, and styles.css into your vault's
plugin folder. (styles.css carries the chip and hover-badge styling.)
Alt+Z to start tally mode at the cursor.Space / + to count up, Backspace / - to count down.Enter to commit a persistent vector chip.Alt+Z) to resume; Esc cancels cleanly.One session at a time; switching leaves ends it without writing.
| Key | Action |
|---|---|
Alt+Z |
Start, or resume the tally under the caret |
Space / + / NumpadAdd / Shift+= |
+1 |
Backspace / - / _ / NumpadSubtract |
−1 (floors at 0) |
Enter |
Commit (single edit) |
Esc |
Cancel, zero document changes |
Ctrl/Alt/Meta chords pass through untouched.
Committed tallies keep rendering as vector chips — same strokes, same metrics,
quieter chrome — across note reopens, plugin reloads, and restarts, derived
purely from the note text. This holds in reading view too (src/reading-tally.ts):
a registerMarkdownPostProcessor pass renders the chip there, because the
editor's CodeMirror decorations never reach Obsidian's MarkdownRenderer.
Reading-view chips are read-only; counting stays an editor action.
Reading rendering verifies ownership against the current Markdown section,
including tallies in the middle of a paragraph. Ordinary unmarked 正 text
and code are left untouched. If another renderer changes the section so its
source cannot be safely matched, the tally remains readable plain text.
Reading rendering never rewrites the note or your settings.
阅读模式按当前区块的源码核对计数归属,也支持段落中间的计数。 没有标记的普通「正」字和代码不受影响。若其他渲染器改变了内容、无法安全核对, 则保留可读的原文字,不猜测计数归属,也不改写笔记或设置。
Enter rewrites text + marker in one edit
(正正正正·3<!--zt:23-->).Esc changes nothing; the original chip returns.Enter removes the tally and its marker.

| Count | Stored |
|---|---|
| 1 | ·1<!--zt:1--> |
| 5 | 正<!--zt:5--> |
| 18 | 正正正·3<!--zt:18--> |
The <!--zt:N--> comment is the integer source of truth and ownership marker.
A marker counts only when it re-serializes to exactly the visible text;
mismatches fail closed. Unmarked legacy tallies (正正正·3) still get a
conservative hover badge and can be resumed once, upgrading on next Enter.
A lone 正 never auto-resumes.
Up to four group slots render in full; beyond that the preview compacts while always keeping the most-recent finished group and the live partial slot:
18 -> 正 正 正 [state3]
20 -> 正 正 正 正
21 -> 正 正 … 正 [state1]
83 -> 正 正 … 正 [state3]
The right-hand total is always exact. Active and persisted chips share one grouping algorithm, so committing never jumps visually.


src/zheng-strokes.ts — vendored canonical 5-stroke vectors (Arphic data)src/renderer.ts — native-measured glyph cells + tally chipssrc/cm6-widget.ts — live inline Decoration.widgetsrc/persistent-tally.ts — marker replace decorations + resume lookupsrc/editor-session.ts — keyboard capture, lifecycle, single-edit commitssrc/tally-hover.ts — legacy parser + transient count badgesrc/tally-state.ts — counts plus stable/marked serializationsrc/editor-host.ts — the single CodeMirror access point正
never badge or resume.npm install # install dependencies
npm run dev # watch mode build
npm run build # production build (dist/main.js + dist/manifest.json)
npm test # 143 passing
npm run lint # eslint
npm run typecheck # tsc --noEmit
正 stroke vectors: Arphic Public License, not MIT —
via Hanzi Writer Data / Make Me a Hanzi, extracted from Arphic Technology
fonts. Full text: vendor/ARPHICPL.txt, notes:
vendor/README.md.