diff --git a/apps/docs/docs.json b/apps/docs/docs.json
index 8a51eb62b1..1945507d18 100644
--- a/apps/docs/docs.json
+++ b/apps/docs/docs.json
@@ -108,7 +108,9 @@
},
"modules/comments",
"modules/toolbar",
- "modules/context-menu"
+ "modules/context-menu",
+ "modules/pdf",
+ "modules/whiteboard"
]
},
{
diff --git a/apps/docs/modules/overview.mdx b/apps/docs/modules/overview.mdx
index 2459ecb8a7..e403960331 100644
--- a/apps/docs/modules/overview.mdx
+++ b/apps/docs/modules/overview.mdx
@@ -34,6 +34,12 @@ const superdoc = new SuperDoc({
Right-click actions and custom commands
+
+ PDF viewer setup and configuration
+
+
+ Annotation layer for documents
+
Each module is configured via `modules.` in the [SuperDoc configuration](/core/superdoc/configuration). See individual module pages for all available options.
diff --git a/apps/docs/modules/pdf.mdx b/apps/docs/modules/pdf.mdx
new file mode 100644
index 0000000000..0f461835ee
--- /dev/null
+++ b/apps/docs/modules/pdf.mdx
@@ -0,0 +1,101 @@
+---
+title: PDF
+keywords: "pdf viewer, pdf.js, pdf rendering, text layer, zoom, annotations"
+---
+
+Render PDFs in SuperDoc. The PDF viewer is configured through `modules.pdf`.
+
+## Install pdf.js
+
+Install `pdfjs-dist` in your app:
+
+```bash
+npm i pdfjs-dist
+```
+
+Supported versions: `>= 5.4.296`.
+
+## Quick start
+
+```javascript
+import { SuperDoc } from 'superdoc';
+import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';
+
+const pathToWorker = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString(); // example in Vite
+
+const superdoc = new SuperDoc({
+ selector: '#viewer',
+ document: fileBlob,
+ modules: {
+ pdf: {
+ pdfLib: pdfjsLib, // required
+ setWorker: true, // auto-configure worker
+ workerSrc: pathToWorker, // path to worker (falls back to CDN if omitted)
+ },
+ },
+ onPdfDocumentReady: () => {
+ console.log('PDF ready');
+ },
+});
+```
+
+## Worker setup (recommended)
+
+This is the recommended approach because the worker is configured once for the whole application.
+
+```javascript
+import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';
+
+pdfjsLib.GlobalWorkerOptions.workerSrc =
+ new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();
+```
+
+Then disable auto-setup:
+
+```javascript
+modules: {
+ pdf: {
+ pdfLib: pdfjsLib,
+ setWorker: false,
+ },
+}
+```
+
+## Configuration
+
+
+ Preloaded pdf.js library instance
+
+
+
+ PDF.js worker source URL (falls back to CDN when omitted)
+
+
+
+ Whether to auto-configure pdf.js worker
+
+
+
+ Enable text layer rendering (for text selection)
+
+
+
+ Canvas render scale (quality)
+
+
+## Events
+
+### `pdf:document-ready`
+
+Fired when all PDF pages are rendered.
+
+```javascript
+superdoc.on('pdf:document-ready', () => {
+ console.log('PDF ready');
+});
+```
+
+## Notes
+
+- `outputScale` affects render quality; zooming does not re-render the canvas.
+- If you need text selection, enable `textLayer: true`.
diff --git a/apps/docs/modules/whiteboard.mdx b/apps/docs/modules/whiteboard.mdx
new file mode 100644
index 0000000000..c24edc6379
--- /dev/null
+++ b/apps/docs/modules/whiteboard.mdx
@@ -0,0 +1,177 @@
+---
+title: Whiteboard
+keywords: "whiteboard, pdf annotations, draw, erase, stickers, text"
+---
+
+Lightweight annotation layer for documents. Supports drawing, text, and stickers.
+
+
+Whiteboard currently works **only with PDF documents**. See [PDF](/modules/pdf) setup first.
+
+
+## Quick start
+
+```javascript
+const superdoc = new SuperDoc({
+ modules: {
+ whiteboard: {
+ enabled: true, // show whiteboard layer by default
+ },
+ },
+});
+```
+
+
+To disable the whiteboard layer entirely, set `modules.whiteboard` to `false`:
+
+```javascript
+modules: {
+ whiteboard: false;
+}
+```
+
+
+## Tools / modes
+
+- **select** — default; select/drag/resize, drop stickers/text
+- **draw** — draw strokes only
+- **erase** — erases strokes only
+- **text** — click to add text
+
+These modes are intentionally strict to avoid ambiguous interactions.
+
+## API methods
+
+All APIs are exposed via `superdoc.whiteboard`.
+
+### `register`
+
+Register palette items (e.g. stickers, comments).
+
+```javascript
+superdoc.whiteboard.register('stickers', [
+ { id: 'check-mark', label: 'Check', src: '/stickers/check-mark.svg', width: 100, height: 83 },
+]);
+
+superdoc.whiteboard.register('comments', [
+ { id: 'great-job', text: 'Great job!' },
+]);
+```
+
+### `getType`
+
+Get registered items by type.
+
+```javascript
+const stickers = superdoc.whiteboard.getType('stickers');
+```
+
+### `setTool`
+
+Set the current tool: `select`, `draw`, `erase`, `text`.
+
+```javascript
+superdoc.whiteboard.setTool('draw');
+```
+
+### `setEnabled`
+
+Enable or disable whiteboard interactivity.
+
+```javascript
+superdoc.whiteboard.setEnabled(true);
+```
+
+### `setOpacity`
+
+Set overlay opacity (0–1).
+
+```javascript
+superdoc.whiteboard.setOpacity(0.8);
+```
+
+### `getWhiteboardData`
+
+Export annotations (normalized coordinates).
+
+```javascript
+const data = superdoc.whiteboard.getWhiteboardData();
+```
+
+### `setWhiteboardData`
+
+Import annotations.
+
+```javascript
+superdoc.whiteboard.setWhiteboardData(json);
+```
+
+### `rerender`
+
+Force re-render for all pages.
+
+```javascript
+superdoc.whiteboard.rerender();
+```
+
+## Events
+
+### `whiteboard:init`
+
+Fired when the whiteboard instance is created.
+
+```javascript
+superdoc.on('whiteboard:init', ({ whiteboard }) => {
+ console.log('Whiteboard instance ready');
+});
+```
+
+### `whiteboard:ready`
+
+Fired when all whiteboard pages are ready.
+
+```javascript
+superdoc.on('whiteboard:ready', ({ whiteboard }) => {
+ console.log('Whiteboard pages ready');
+});
+```
+
+### `whiteboard:change`
+
+Fired on any data change. Receives full whiteboard JSON.
+
+```javascript
+superdoc.on('whiteboard:change', (data) => {
+ console.log(data);
+});
+```
+
+### `whiteboard:enabled`
+
+Fired when interactivity is toggled.
+
+```javascript
+superdoc.on('whiteboard:enabled', (enabled) => {
+ console.log(enabled);
+});
+```
+
+### `whiteboard:tool`
+
+Fired when the active tool changes.
+
+```javascript
+superdoc.on('whiteboard:tool', (tool) => {
+ console.log(tool);
+});
+```
+
+## Import / export
+
+Whiteboard data is stored in normalized coordinates so annotations stay stable across zoom levels.
+
+```javascript
+const saved = superdoc.whiteboard.getWhiteboardData();
+
+superdoc.whiteboard.setWhiteboardData(saved);
+```
diff --git a/apps/docs/scripts/validate-code-imports.ts b/apps/docs/scripts/validate-code-imports.ts
index 5587dd0a29..0e8855199a 100644
--- a/apps/docs/scripts/validate-code-imports.ts
+++ b/apps/docs/scripts/validate-code-imports.ts
@@ -37,6 +37,8 @@ const EXACT_EXTERNAL_IMPORTS = new Set([
'react-dom',
'react-dom/client',
'vue',
+ 'pdfjs-dist',
+ 'pdfjs-dist/build/pdf.mjs',
'yjs',
'y-prosemirror',
'y-websocket',