The citation link format
A ForkLeaf citation is an ordinary Markdown link. Nothing about it is proprietary and nothing about it needs this app: a relative path, plus a fragment made of the #page= convention every PDF reader has understood for twenty years and the W3C Web Annotation text selector. This page writes it down so that anything else — an Obsidian plugin, Zotero, a static site, a script — can read and write the same links.
The shape of one
This is a whole citation, as it lands in a note:
> Attention is all you need, and the rest is engineering.
>
> — [On Attention, p. 12](../papers/attention.pdf#page=12&q=Attention%20is%20all&pre=We%20show%20that&suf=%2C%20and%20the%20rest)The blockquote is the passage as it was read. The line under it is a Markdown link whose destination has two halves: a path, relative to the note holding it, and a fragment.
The fragment
Fields are key=value pairs joined by &, percent-encoded, in any order. An unknown key is ignored rather than treated as an error.
| Field | Means | Required |
|---|---|---|
page | The 1-based page the passage was on when the link was written. A hint, never the authority. | One of page or q |
q | The quoted text itself, as it appeared on the page. Up to 512 characters. | One of page or q |
pre | Up to 48 characters immediately before the quotation, for telling two occurrences apart. | No |
suf | Up to 48 characters immediately after it, for the same reason. | No |
p is accepted as a synonym for page, and quote for q. A bare #12 means page 12, because that is what people type.
Why the quotation and not just the page
A page number is a claim that quietly stops being true. The author adds a figure to page 4 and every citation after it points one page short — the link still opens, it just shows the wrong paragraph, and nothing tells you. Storing the sentence makes the link checkable: search the document as it stands now for those words, and use the page only as a hint about where to start looking.
How ForkLeaf resolves one
- Normalise the document’s text and the quotation the same way — ligatures folded (
fitofi), hyphenation across line breaks joined, runs of whitespace collapsed. This is what makes a search for “find” match a page that really containsfind. - Look for the quotation, preferring the recorded page, then the pages around it, then the whole document.
- Where several occurrences match,
preandsufchoose between them. That is what context is for: in a paper that says “as discussed above” forty times, the quotation alone identifies nothing. - Report the outcome honestly — found where it said, found on another page, found only after normalising, or not found at all. A resolver that silently falls back to “whatever is on page 12 now” is the behaviour this format exists to avoid.
Writing one
Select a passage in ForkLeaf’s reader and press Copy link to put exactly this form on the clipboard. To generate one elsewhere: take the selected text, the 48 characters either side of it, and the page it is on; percent-encode each; and join them onto the file’s path.
papers/attention.pdf#page=12&q=Attention%20is%20all%20you%20needSupporting it in another tool
Reading these links is worth more than writing them, and it is the smaller job. A tool that already opens PDFs at a page needs only to notice q, search for it, and prefer what it finds over the page number.
- Ignore what you do not use. A reader that only understands
#page=behaves exactly as it does today; the extra fields cost it nothing. - Do not require the fields to be in order. They are a query string, not a format.
- Treat the page as a hint. If the quotation is elsewhere in the document, the quotation is right and the page is stale.
If you are building something that reads or writes these, we would like to hear about it — tell us, and if the format is missing something you need, say so while it is still small enough to change.