Annotate
Add multi-color labels to different fragments of the same line / same passage — visualize "syntax analysis, code walkthrough, contract clause review, line-by-line poetry annotation" inside markdown.
When to use
- ✅ Syntax analysis — color-code subject / verb / object in a sentence
- ✅ Code walkthrough — highlight tokens in one code line + label each
- ✅ Contract clause review — flag key clauses, risky clauses, obligations
- ✅ Poetry annotation — mark allusions, rhymes, imagery individually
- ✅ Translation alignment — show which fragment of source maps to which translated chunk
- ❌ Heavy annotation across long passages — visual overload; use multiple callouts instead
- ❌ Annotation needs "fold / hide / click to reveal" — use Modal
Basic syntax
annotate is a fenced code block in two halves — body + --- separator + annotation table:
```annotate
The quick brown fox jumps over the lazy dog
---
4-9|red|adjective
10-15|blue|noun
16-21|green|verb
```
Renders: the original sentence is intact, but quick (chars 4-9) gets a red underline, brown (10-15) blue, jumps (16-21) green. Hover any fragment to see the label as a tooltip.
Syntax details
Body
The body is usually one line or a short passage. Multi-line is supported, but character positions count newlines too.
Separator
--- (three hyphens on their own line) — the annotation table follows immediately.
Annotation entries
One per line, formatted as:
<start>-<end>|<color>|<label>
<start>/<end>— character positions, 0-based half-open (see "All options" below)<color>— color (1 of 6, same as Layout accent palette)<label>— tooltip text on hover (any text, but cannot contain|)
All options
Position numbering
| Mode | Range meaning | Example |
|---|---|---|
| 0-based half-open (only mode) | [start, end) |
0-3 covers [0,1,2] (3 chars) |
Positions are always 0-based, half-open — matches JS / Python string slice semantics. No alternate inclusive numbering mode exists.
Color palette
| Value | Visual | Recommended |
|---|---|---|
red |
Red | Error / warning / critical |
blue |
Blue | General annotation / neutral emphasis |
green |
Green | Passing / recommended / correct |
yellow |
Yellow | Attention / pending review |
purple |
Purple | Special / advanced |
gray |
Gray | Low weight / weak annotation |
Same 6 colors as Layout accent — easy to keep visual consistency across a page.
Examples
Example 1: English syntactic analysis
```annotate
The quick brown fox jumps over the lazy dog.
---
0-3|gray|definite article
4-15|blue|adjective phrase
16-19|green|subject (noun)
20-25|red|verb (action)
26-30|gray|preposition
31-43|purple|object (noun phrase)
```
Renders: each syntactic role gets a distinct underline color; hover reveals the role label. The whole sentence structure is visible at a glance: article → adjective phrase → subject → verb → preposition → object.
Example 2: code walkthrough, token by token
```annotate
const result = await fetch('/api/users').then(r => r.json());
---
0-5|purple|declaration (const)
6-12|blue|variable name
15-20|red|keyword (await)
21-26|green|builtin function
28-39|yellow|URL string
42-46|red|Promise chain (.then)
47-58|gray|arrow function
```
Renders: each token in this single line of JS gets a category label. Adds one layer beyond ordinary syntax highlighting — readers see "this is a declaration / this is async keyword / this is a Promise chain" as semantic roles, not just "this is a keyword / this is a string."
Example 3: poetry, character-by-character
```annotate
床前明月光,疑是地上霜。
---
0-2|blue|imagery: bed (home, intimacy)
2-4|gray|directional
4-6|yellow|imagery: bright moon (homesickness symbol)
7-8|gray|verb: 疑 (haze / illusion)
9-10|gray|copula: 是
10-12|blue|imagery: ground (mortal world / reality)
12-13|yellow|imagery: frost (cold, lonely)
```
Renders: every character / phrase in a Tang poem gets imagery, part-of-speech, or cultural symbol notes. Hover each colored region for the gloss — like a modern interactive version of "line-by-line classical commentary."
Example 4: contract risk annotation
```annotate
This Agreement enters into force upon signing by both parties, with a 5-year term and auto-renewal upon expiry.
---
0-13|gray|subject: This Agreement
14-46|blue|effective condition
47-62|yellow|term (5 years)
63-86|red|⚠️ auto-renewal clause (high risk; recommend "requires written confirmation to renew")
```
Renders: contract key clauses are color-coded by category; "auto-renewal" gets a red high-risk mark + detailed review note. Markdown becomes a usable tool for legal review.
Plain-text fallback behavior
annotate is a fenced code block. In readers without support:
```annotate
The quick brown fox jumps over the lazy dog.
---
0-3|gray|definite article
4-15|blue|adjective phrase
...
```
→ shows as a syntax-highlighted code block — readers can see the full original sentence + annotation table, and manually correlate character positions with colors to understand the annotation. Information is preserved; only the visualization is lost.
Per-reader breakdown:
| Reader | Render |
|---|---|
| Rho | Full visualization (colored underlines + tooltips) |
| GitHub web | Code block (annotate lang label, no matching highlighter, plain text) |
| Obsidian | Same |
| VS Code default preview | Same |
| cat / less | Plain text |
Common pitfalls
1. Wrong character counting
Chinese / emoji / composite characters can trip you up:
床前明月光
| Position | Character |
|---|---|
| 0 | 床 |
| 1 | 前 |
| 2 | 明 |
| 3 | 月 |
| 4 | 光 |
One Chinese character = one position (not 3 bytes). Rho counts by Unicode codepoints.
But emoji and composite emoji (flags, families) may count multiple positions:
| Character | Codepoints |
|---|---|
😀 |
1 |
👨👩👧 (family) |
5 (with ZWJ joiners) |
🇨🇳 (flag) |
2 |
For composite emoji, verify with JS [...str].length before annotating.
2. Range exceeds body length
Body is 5 chars long, but you wrote 4-10
→ Rho truncates to body end (no error), but the visual is unpredictable. Count first.
3. Overlapping ranges
0-5|red|fragment A
3-8|blue|fragment B ← ❌ Overlaps A at [3,5)
→ Overlapping regions have undefined render behavior (later may overwrite earlier, or colors stack — depends on the reader). Annotations should not overlap. If you genuinely need "nested semantics," split into two annotate blocks (repeat the body in both).
4. Label contains |
0-5|red|risk: A | B | C ← ❌ Pipe is a separator
→ The parser splits into 5 segments — all wrong. Labels can't contain |.
Fix: use /, ,, comma, or the full-width |.
5. Forgot the --- separator
```annotate
The quick brown fox
0-3|gray|definite article ← ❌ Missing ---, treated as part of body
```
→ The whole block becomes "an unparseable thing." Body and annotation table must be separated by --- on its own line.
6. Using annotate for a long paragraph
If you want to annotate 20 fragments across 300 words, don't cram it into one annotate block — visual overload, hard to find tooltips, character positions become unmaintainable. Fix: split the paragraph into sentences and use one annotate block per sentence. Or switch to "paragraph + footnotes" with regular markdown.
See also
- Callout — Whole-passage emphasis (not in-line fragment)
- STL syntax highlighting — Built-in STL grammar coloring (not manual annotate)
- Modal — When you need "click to reveal" annotation
- Layout grid + cards — accent color shares the same 6-color palette as annotate
- Plain-text fallback principle