Agent skill

Developing PDF Viewer

by TriliumNext in TriliumNext/Trilium

A skill your agent uses when changing Trilium's built-in PDF viewer — anything under packages/pdfjs-viewer (the code injected into Mozilla's PDF.js viewer: bootstrap.ts, annotations.ts, pages.ts…

AGPL-3.0Auto-check passedDocuments & Office

Install Developing PDF Viewer

skills CLI
$ npx skills add TriliumNext/Trilium --skill developing-pdf-viewer -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install TriliumNext/Trilium developing-pdf-viewer --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/developing-pdf-viewer .claude/skills/developing-pdf-viewer && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
developing-pdf-viewer
GitHub stars
38k
Token cost
~1.8k tokens
SKILL.md length
815 words
Files
1
Skills in repo
22
Repo updated
First seen
Licence
AGPL-3.0

At a glance

A skill your agent uses when changing Trilium's built-in PDF viewer — anything under packages/pdfjs-viewer (the code injected into Mozilla's PDF.js viewer: bootstrap.ts, annotations.ts, pages.ts…

  • Changing Triliums built-in PDF viewer — anything under packages/pdfjs-viewer (the code injected into Mozillas PDF.js viewer: bootstrap.ts
  • SKILL.md covers Rebuild the viewer after every…, The message protocol, The viewer outlives the note… and pdf.js timing traps, plus 1 more section
  • Calls pnpm
  • The client side that talks to it (apps/client/src/widgets/typewidgets/file/Pdf.tsx

What it does

Developing PDF Viewer is an agent skill from TriliumNext/Trilium. Use when changing Trilium's built-in PDF viewer — anything under packages/pdfjs-viewer (the code injected into Mozilla's PDF.js viewer: bootstrap.ts, annotations.ts, pages.ts, toc.ts, layers.ts, attachments.ts, persistence.ts, editing.ts), the client side that talks to it (apps/client/src/widgets/typewidgets/file/Pdf.tsx, PdfViewer.tsx, the sidebar panels in widgets/sidebar/pdf/), the postMessage protocol between them, PDF links (?page= / ?annotation=), or a bug where the viewer "does not pick up" a change…

Its SKILL.md is about 1.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Documents & Office, covering PDF and React components. It works with pnpm. The repository describes itself as: Build your personal knowledge base with Trilium Notes. The licence is AGPL-3.0.

When your agent uses it

  • Changing Triliums built-in PDF viewer — anything under packages/pdfjs-viewer (the code injected into Mozillas PDF.js viewer: bootstrap.ts
  • The client side that talks to it (apps/client/src/widgets/typewidgets/file/Pdf.tsx
  • The sidebar panels in widgets/sidebar/pdf/)
  • The postMessage protocol between them

Example prompts

  • “does not pick up”
  • “/developing-pdf-viewer”

What it can do on your machine

Read from SKILL.md and the folder at commit cac2b4f. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pnpm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Developing PDF Viewer loads about 1.8k tokens when it runs. Until then it costs about 182 tokens; SKILL.md has 815 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~182
When it runs · the whole SKILL.md, loaded when a task matches
~1.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from TriliumNext/Trilium at commit cac2b4f, republished under its AGPL-3.0 licence (© TriliumNext). 815 words, ~1,792 tokens.

Download SKILL.mdSave it as .claude/skills/developing-pdf-viewer/SKILL.md (or your agent's skills folder).
name
developing-pdf-viewer
description
Use when changing Trilium's built-in PDF viewer — anything under `packages/pdfjs-viewer` (the code injected into Mozilla's PDF.js viewer: `bootstrap.ts`, `annotations.ts`, `pages.ts`, `toc.ts`, `layers.ts`, `attachments.ts`, `persistence.ts`, `editing.ts`), the client side that talks to it (`apps/client/src/widgets/type_widgets/file/Pdf.tsx`, `PdfViewer.tsx`, the sidebar panels in `widgets/sidebar/pdf/`), the postMessage protocol between them, PDF links (`?page=` / `?annotation=`), or a bug where the viewer "does not pick up" a change. Covers the mandatory rebuild after every viewer change, the message protocol, the hidden-but-mounted viewer, the pdf.js timing traps, and how to test at each level.

Developing the PDF viewer

A PDF note renders in an iframe running Mozilla's PDF.js viewer, vendored in packages/pdfjs-viewer/viewer/ (viewer.mjs, viewer.html, refreshed by pnpm --filter @triliumnext/pdfjs-viewer update-viewer) plus Trilium's own code in packages/pdfjs-viewer/src/, bundled into web/custom.mjs. The client never imports that code: Pdf.tsx and the viewer talk only through postMessage.

Rebuild the viewer after every change to it

After any edit under packages/pdfjs-viewer/ (src/, viewer/, scripts/), run the build before testing anything in an app:

bash
pnpm --filter @triliumnext/pdfjs-viewer build

Every app serves the built packages/pdfjs-viewer/dist, never the sources: the server in development (getPdfjsAssetDir() in apps/server/src/routes/assets.ts), desktop, and standalone (apps/standalone/vite.config.mts). dist is built only by the root prepare script, i.e. on pnpm install; pnpm server:start and the other *:start scripts do not rebuild it and do not watch it. Vite hot-reloads the client half of a change while the viewer half stays at whatever was built last, so a stale dist looks exactly like a bug in the new code — or like a fix that works, when the old viewer happens to behave. Check the age when in doubt:

bash
ls -l --time-style=+%H:%M packages/pdfjs-viewer/dist/web/custom.mjs
  • For a longer session, pnpm --filter @triliumnext/pdfjs-viewer watch rebuilds custom.mjs on save. Then reload the app page: the iframe loads the viewer afresh with the note.
  • The viewer's own Playwright suite (pnpm --filter @triliumnext/pdfjs-viewer e2e) builds before serving, but reuseExistingServer keeps a harness server that is already running — and its stale bundle — outside CI.
  • The unit specs (pnpm --filter @triliumnext/pdfjs-viewer test) import the sources directly and need no build. Green specs therefore say nothing about what an app serves.
  • When reporting a viewer change done, say that dist was rebuilt, so the user's running instance picks it up on reload.

The message protocol

  • Viewer → client: pdfjs-viewer-* messages, typed in apps/client/src/types-pdfjs.d.ts (PdfMessageEvent). Every message carries noteId and ntxId (from the iframe URL, set in bootstrap.ts), and Pdf.tsx drops any message not addressed to its own note and context, because every viewer posts to the same parent window.
  • Client → viewer: trilium-* messages, posted to iframeRef.current.contentWindow; the viewer checks event.origin. They are not typed on the viewer side.
  • Pdf.tsx turns the viewer's data into note-context data (toc, pdfPages, pdfAnnotations, pdfAttachments, pdfLayers), which the right sidebar panels read with useGetContextData(). Write it through publish(), not noteContext.setContextData() — see below.
  • Most setup runs on pdf.js documentloaded and only when the note is editable (bootstrap.ts); setupPdfAnnotations() runs for read-only PDFs too. The first pdfjs-viewer-annotations message is the client's signal that the viewer can scroll.

The viewer outlives the note it shows

NoteDetailWrapper keeps each type widget mounted, hidden, while the pane shows a note of another type, so a PDF → text note → same PDF round trip reuses the iframe with its document loaded. Two consequences:

  • NoteContext.setNote() clears the context data on the way out, and the viewer never sends it again. Pdf.tsx keeps what it last received per key and republishes it when isVisible turns true; anything new published while hidden is recorded, not written.
  • Anything that scrolls must wait for isVisible: a hidden viewer throws "offsetParent is not set -- cannot scroll" and the scroll is lost. noteSwitched reaches the hidden viewer before it is shown.
Show full SKILL.md (303 more words)Show less

pdf.js timing traps

  • The initial view undoes an early scroll. pdf.js restores the last-read position at documentinit and, for pages of unequal size, again after pagesPromise. trackInitialView() in annotations.ts makes scrollToAnnotation() wait for both.
  • A resize scrolls back to the recorded position. onResize() reapplies an auto, page-fit or page-width zoom and #setScaleUpdatePages() scrolls to _location, which pdf.js records in pdfViewer.update() on the next frame's scroll event. A viewer shown again resizes, often in the same frame as a jump. After a programmatic scroll, call pdfViewer.update() and scroll instantly, never smoothly.
  • An annotation's element is not a reliable target. Pages render only near the viewport, and while an annotation tool is active pdf.js hides each editable annotation's element behind an editor. Position from the rectangle (page.getAnnotations(), or annotationStorage.serializable for what was edited in this session) through pageView.viewport.convertToViewportPoint(); pdf.js 6 has no convertToViewportRectangle().
  • Ids drawn this session are temporary. A stored annotation's id is its object reference (12R); one drawn since the document loaded has an editor id (pdfjs_internal_editor_N) that the next load does not reuse.

Testing

LevelWhatCommand
Viewer unitsrc/*.spec.ts against real pdf.js and a thin PDFViewerApplication (src/test/viewer_app.ts, fixture PDF in src/test/fixture_pdf.ts)pnpm --filter @triliumnext/pdfjs-viewer test --run
Client unitPdf.spec.tsx (the protocol, with PdfViewer mocked), sidebar panel specspnpm --filter client test src/widgets/type_widgets/file/Pdf.spec.tsx src/widgets/sidebar/pdf/
Viewer e2ebuilt bundle + a stub parent (e2e/harness)pnpm --filter @triliumnext/pdfjs-viewer e2e
Appin-memory e2e fixture with Dacia Logan.pdf (oUfFD9lugwiQ) and Layers test.pdf (n7gU3aBDPKd9)see building-client-ui → references/inspecting-the-running-app.md — rebuild dist first

A timing bug (a jump undone, a panel empty after navigation) usually passes in a fast headless run. Instrument the iframe (contentWindow resize listener, PDFViewerApplication.pdfViewer _location / currentScale, a wrapped postMessage) to read the order of events, then force the losing order in the repro — for example resize the iframe right after the client posts — before trusting a fix.

© TriliumNext, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/developing-pdf-viewer of TriliumNext/Trilium.

Open the folder on GitHubat commit cac2b4f

Compare with similar skills

Developing PDF Viewer next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Developing PDF Viewer compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Developing PDF Viewer this skillTriliumNext/Trilium38k—~1.8kAutomated safety check: PassAGPL-3.0
Create Rich Text Editor Custom Nodegetlago/lago-front163—~2kAutomated safety check: NotesAGPL-3.0
Build With SimplepdfSimplePDF/simplepdf-embed407—~7kAutomated safety check: PassMIT
React PDFtrailofbits/skills-curated512—~3.1kAutomated safety check: NotesCC-BY-SA-4.0
MarkitdownImCa0/just-laws78114 repos~3.2kAutomated safety check: NotesMIT
Gzh Designisjiamu/gzh-design-skill3.9k1 repos~2.2kAutomated safety check: PassAGPL-3.0

Similar skills

  • Create a new custom TipTap node for the Rich Text Editor that works in edit mode, on-screen preview, and PDF download.

    163 GitHub stars~2k tokensUpdated today
    Documents & OfficeAuto-check: notes
  • Build With Simplepdf

    SimplePDF/simplepdf-embed

    Integrate SimplePDF into a web application for PDF viewing, editing, filling, signing, programmatic control, AI-agent interaction, human-in-the-loop form prefilling, submissions, webhooks, or…

    407 GitHub stars~7k tokensUpdated 7 days ago
    Documents & OfficeAuto-check passed
  • React PDF

    trailofbits/skills-curated

    Official

    Generates PDF documents using the React-PDF library (@react-pdf/renderer) with TypeScript and JSX.

    512 GitHub stars~3.1k tokensUpdated 2 mo ago
    Documents & OfficeAuto-check: notes
  • Markitdown

    ImCa0/just-laws

    Convert files and office documents to Markdown. An agent skill from ImCa0/just-laws.

    781 GitHub starsUsed in 14 repos~3.2k tokens
    Documents & OfficeAuto-check: notes
  • Gzh Design

    isjiamu/gzh-design-skill

    微信公众号文章排版引擎,将 Markdown 转换为可直接粘贴到公众号编辑器的 HTML。主题风格从 references/theme-index.md 注册的自定义主题库中选取,自动章节编号、关键词下划线标记、引言卡片、目录导航、代码块、图片/GIF、作者签名。支持 Markdown / Word(.docx) / PDF / 纯文本输入(非 Markdown…

    3.9k GitHub starsUsed in 1 repo~2.2k tokens
    Documents & OfficeAuto-check passed
  • @pierre/diffs Code Rendering

    pierrecomputer/pierre

    Guides an agent through using @pierre/diffs to render syntax-highlighted files and diffs, and to build editing and review surfaces in React or plain JavaScript.

    6.2k GitHub starsUsed in 2 repos~803 tokens
    DevelopmentAuto-check passed

More from TriliumNext/Trilium

All 22 skills in this repo
  • Cutting A Release

    TriliumNext/Trilium

    A skill your agent uses when cutting, preparing, or debugging a Trilium release — bumping the monorepo version, tagging, or diagnosing a failed "Release" workflow run.

    38k GitHub stars~3.2k tokensUpdated today
    Auto-check passed
  • Developing Electron Desktop

    TriliumNext/Trilium

    A skill your agent uses when working on the Trilium Electron desktop app (apps/desktop) — adding or changing an electronApi method / IPC channel, touching preload.ts, main.ts, services/window.ts or…

    38k GitHub stars~5.7k tokensUpdated today
    Auto-check passed
  • Evolving The Data Model

    TriliumNext/Trilium

    A skill your agent uses when adding a DB migration or a new column/field to a Becca entity in Trilium ("add a migration", "new column on notes/attributes", "ALTER TABLE", "add a field to…

    38k GitHub stars~2.1k tokensUpdated today
    Auto-check passed
  • Adding Internal API Route

    TriliumNext/Trilium

    A skill your agent uses when adding, moving, or wiring an internal REST endpoint in Trilium (a new /api/ route) — choosing between a core-shared handler (packages/trilium-core/src/routes/index.ts…

    38k GitHub stars~3.3k tokensUpdated today
    Auto-check passed
  • Adding LLM MCP Tools

    TriliumNext/Trilium

    A skill your agent uses when adding, changing, or reviewing an LLM/MCP tool in Trilium (the defineTools definitions under packages/trilium-core/src/services/llm/tools/ —…

    38k GitHub stars~2.5k tokensUpdated today
    Auto-check passed
  • Ckeditor5 Plugin Development

    TriliumNext/Trilium

    Write, extend, and review CKEditor 5 plugins in the Trilium (TriliumNext Notes) monorepo — the rich-text-note editor under packages/ckeditor5, whose plugins live in src/plugins/.

    38k GitHub stars~4.8k tokensUpdated today
    Auto-check passed

Works with

Questions about Developing PDF Viewer

What does Developing PDF Viewer do?

A skill your agent uses when changing Trilium's built-in PDF viewer — anything under packages/pdfjs-viewer (the code injected into Mozilla's PDF.js viewer: bootstrap.ts, annotations.ts, pages.ts…. Developing PDF Viewer is an agent skill from TriliumNext/Trilium.

When should I use Developing PDF Viewer?

Developing PDF Viewer fits situations like: changing Triliums built-in PDF viewer — anything under packages/pdfjs-viewer (the code injected into Mozillas PDF.js viewer: bootstrap.ts; the client side that talks to it (apps/client/src/widgets/typewidgets/file/Pdf.tsx; the sidebar panels in widgets/sidebar/pdf/); the postMessage protocol between them.

How do I install Developing PDF Viewer in Claude Code?

Run `npx skills add TriliumNext/Trilium --skill developing-pdf-viewer -a claude-code`. Or copy the skill folder (.claude/skills/developing-pdf-viewer in TriliumNext/Trilium) into .claude/skills/developing-pdf-viewer in your project. Claude Code loads it when a task matches its description.

How do I install Developing PDF Viewer in Codex?

Run `npx skills add TriliumNext/Trilium --skill developing-pdf-viewer -a codex`. Or copy the skill folder (.claude/skills/developing-pdf-viewer in TriliumNext/Trilium) into .agents/skills/developing-pdf-viewer in your project. Codex loads it when a task matches its description.

Can I use Developing PDF Viewer in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add TriliumNext/Trilium --skill developing-pdf-viewer -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/developing-pdf-viewer, .gemini/skills/developing-pdf-viewer, .github/skills/developing-pdf-viewer and .opencode/skills/developing-pdf-viewer in your project.

What does Developing PDF Viewer need to run?

Going by SKILL.md and its folder, Developing PDF Viewer needs the command-line tools its instructions call (pnpm).

Does Developing PDF Viewer access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Developing PDF Viewer safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Developing PDF Viewer use?

Developing PDF Viewer is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Developing PDF Viewer use?

About 1.8k tokens (SKILL.md is roughly 7.2k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Developing PDF Viewer?

Skills that share tags, products or a category with Developing PDF Viewer: Create Rich Text Editor Custom Node (getlago/lago-front, 163 stars), Build With Simplepdf (SimplePDF/simplepdf-embed, 407 stars), React PDF (trailofbits/skills-curated, 512 stars) and Markitdown (ImCa0/just-laws, 781 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Developing PDF Viewer?

TriliumNext (a GitHub organization) maintains it in TriliumNext/Trilium, which has 38,248 GitHub stars. The repository holds 22 skills in this directory. The repository was last updated on October 8, 2026.

Source: TriliumNext/Trilium on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.