sean-3901k downloadsAnnotate and ask questions about the text or region you select, in notes and PDFs, without leaving the page. Annotations live in their own Markdown files and stay linked to the source; the original document is never modified.
Annotate and ask questions about what you select — in notes and in PDFs — without leaving the page.
English | 中文
Select text in a note, or drag a rectangle over a PDF page, and a panel opens right there: pick a template or ask your own question. Every annotation lives in its own Markdown file and stays linked to the source — the original document is never modified, not a single byte.
| Select and ask | The answer, stored with the annotation |
|---|---|
![]() |
![]() |
![]() |
![]() |
In a PDF you can annotate two ways, and the toolbar switches between them: drag a rectangle over a region (its text and a screenshot go to the model together), or drag a highlighter stroke across text — the stroke snaps to the lines underneath and renders as a clean band, however shaky your hand was. The two have distinct jobs: the highlighter just highlights — while you drag you see your own stroke, it snaps into a clean band on release, only the stretch you actually painted is covered, and nothing pops up; click the highlight when you want to attach a one-line note (or switch that box to the question composer with “Ask AI instead”). Dragging straight down highlights whole lines, and starting the next stroke on an existing highlight (or the line next to it) merges into it, so reading down a paragraph builds one multi-line highlight. A rectangle never merges and opens the ask panel the moment you finish it. Which one is live is visible both on the toolbar (the active icon keeps an accent background) and in the pointer: crosshair for a region, a marker for the highlighter. The two can be combined on the same annotation.
Drag a rectangle over a PDF page — the text of that region and its screenshot go to the model together, and the box stays on the page to reopen later:

<your-github-user>/pickme.main.js, manifest.json and styles.css into <vault>/.obsidian/plugins/pickme/, then enable it in Settings.Desktop only (isDesktopOnly) — the built-in pdf.js viewer and region screenshots need desktop capabilities.
This plugin collects nothing and has no telemetry. It does need network access to the model endpoint you configure:
.obsidian/plugins/pickme/data.json, like any other Obsidian plugin's settings. It is never sent anywhere except the endpoint you configured.pickme_include_note).main.js at build time..obsidian/plugins/pickme/: annotation files, templates, the generated index) and reads nothing outside the vault.Interactions happen on the page. The sidebar is only for reviewing existing annotations.
× or Esc. A box you just drew that has no question yet is undone when you close the panel; once you have asked something it stays.All pages sit in one scroll container, like the built-in PDF reader: the scrollbar represents the whole document, and the page box follows it.
| Way to move | How |
|---|---|
| Wheel / trackpad | Scroll continuously; PageUp/PageDown/Home/End scroll natively |
| Buttons / page box | Toolbar previous/next page, or type a page number and press Enter |
| Trackpad swipe | Swipe sideways to flip a page (needs ~120px so it doesn't fire by accident) |
| Keyboard | ← / → flip pages (the page box keeps focus; when zoomed in far enough to scroll sideways, arrows stay native) |
Only pages near the viewport are rendered; far-away canvases are released and repainted when you scroll back, so a 100-page PDF does not eat hundreds of MB.
Outline: PDFs with bookmarks (usually standards, manuals, datasheets) get an outline panel on the left; click an entry to jump to that page. PDFs without bookmarks get no outline button at all. The open/closed state is remembered.
The toolbar is grouped by function, left to right, separated by hairline dividers: outline (only when the PDF has bookmarks) | paging (previous / page box / page count / next) | zoom (out / percentage / in / fit width — click the percentage to snap back to 100%) | display (highlight toggle: turn it off for a clean PDF). Toolbar buttons are icon-only with tooltips, and the grey text at the far right is the current status (it ellipsizes when narrow).
Run the command Open annotation index to get a sidebar listing every annotation in the vault, grouped by source document: selection snippet or PDF page, question count, anchor id and creation time.
Stale (N) row at the end of each group, with the reason spelled out. Use the command Rebind stale anchors to re-attach one by re-selecting the text in the source.annotations-index.md summary inside its own (hidden) plugin folder — an internal artifact with no setting; handlers that want it can point Dataview at the plugin folder.A template is just a prompt. Three are built in — Explain / Summarize / Translate — and every .md file in the template folder is a template; the file name is the name in the dropdown.
Variables: {{选区}} (selection), {{提问}} (question), {{上下文}} (context), {{笔记标题}}, {{源路径}}, {{页码}}, {{已有批注}}, {{区域图片}}. A line whose variables are all empty is dropped entirely, so optional paragraphs are safe.
Frontmatter can override per-template behaviour:
pickme_model: qwen/qwen3.8-flash-next # model for this template (empty = default)
pickme_temperature: 0.7 # override temperature
pickme_include_note: false # also send the whole note
pickme_vision: true # send the PDF region screenshot
pickme_context: false # attach surrounding context
Point the plugin at any OpenAI-compatible endpoint (official API, a gateway, an intranet service). The settings cover the base URL, API key, default model, temperature, streaming, deep thinking, an optional vision model, and the maximum output length. Test connection sends a minimal request to check the credentials.
Two things worth knowing:
Full section-by-section explanation of every setting: README.zh.md (Chinese).
main.js is about 3.8 MB because pdf.js's CMap tables and standard fonts are inlined — the price of needing no network for PDF rendering. They ship as one gzip stream per group and are decompressed once, on demand, so the download stays as small as this feature allows.requestAnimationFrame and pdf.js rendering pauses; it repaints when the window returns.<pickme id="xxxxxx"></pickme>) but hidden in editing and reading views.npm install
npm run dev # watch build
npm run verify # typecheck + unit tests + build + smoke test
npm run build # produce main.js
node scripts/install.mjs "/path/to/vault" # symlink the project into a vault (dev)
node scripts/install.mjs "/path/to/vault" --copy # copy the built files instead
The repository ships the plugin source and build scripts only. Design and acceptance documents stay in the private development repository.
src/generated/pdfAssets.ts (pdf.js CMap tables and standard fonts, ~1.8 MB of base64) is committed on purpose: static analysis and type checking have to resolve it, and an unresolved import degrades to any, which shows up as spurious unsafe-* findings in the plugin review. Regeneration is deterministic, and CI fails if it drifts from pdfjs-dist.
[email protected], Apache-2.0) for PDF rendering; its CMap tables and standard fonts are inlined by scripts/inline-pdf-assets.mjs.new Function. Pick Me disables them (isEvalSupported: false in src/pdf/pdfjs.ts), so no generated code is ever evaluated — the automated review still shows a "dynamic code execution" note because that code is present in the bundle.