12og3r/Pdfine

A private, browser-based PDF editor that lets you directly edit text in PDFs while preserving the original typography — fonts, sizes, weights, and colors. Everything runs locally in your browser. No uploads. No accounts. No compromises.

★ 0Forks 0JavaScriptGitHub ↗Compare

README


██████╗ ██████╗ ███████╗██╗███╗   ██╗███████╗
██╔══██╗██╔══██╗██╔════╝██║████╗  ██║██╔════╝
██████╔╝██║  ██║█████╗  ██║██╔██╗ ██║█████╗  
██╔═══╝ ██║  ██║██╔══╝  ██║██║╚██╗██║██╔══╝  
██║     ██████╔╝██║     ██║██║ ╚████║███████╗
╚═╝     ╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═══╝╚══════╝

Edit PDFs directly in the browser — typography preserved, privacy guaranteed.

All parsing, editing, reflow, and export happen 100% client-side.
No uploads. No accounts. No backend.


Live Demo

Client-Side No Uploads Privacy First


License: GPL v3 TypeScript React Vite




✦ Showcase

Pdfine Landing Page
Clean, luminous landing with animated gradient orbs, 3D tilt upload widget, and shine-sweep hover effect


✦ Why Pdfine?

🔒 Truly Private

Your files never leave your device. All parsing, editing, and exporting happen entirely in the browser. No server. No telemetry. Nothing leaves localhost.

🔤 Typography Preserved

Edit text while keeping the original fonts, sizes, weights, and colors intact. Automatic text reflow with PDF-native line heights and per-line character widths — text stays exactly where it was.

⚡ Zero Setup

No accounts. No installations. No backend to deploy. Open the page, drop a PDF, start editing. That's it.

🎯 Pixel-Perfect

Canvas-based rendering with character-level precision. What you see is exactly what you get in the exported PDF.

✂️ Full Editing

Cursor navigation, text selection, copy/paste, undo/redo, IME input (CJK), and keyboard shortcuts. Enter to confirm, Shift+Enter for new lines, Escape to cancel.

📦 One-Click Export

Save your edits as a new PDF with embedded fonts, preserving the original document structure and visual fidelity.


✦ Tech Stack

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│   │ React 19 │  │   TS 5.9 │  │  Vite 7  │  │Zustand 5 │  │
│   └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘  │
│        │              │             │              │        │
│   ┌────┴──────────────┴─────────────┴──────────────┴────┐   │
│   │               Canvas Rendering Engine               │   │
│   └────┬──────────────┬─────────────┬───────────────────┘   │
│        │              │             │                       │
│   ┌────┴─────┐  ┌─────┴────┐  ┌────┴─────┐                │
│   │ pdfjs-   │  │  pdf-lib  │  │ opentype │                │
│   │ dist     │  │          │  │   .js    │                │
│   │ (parse)  │  │ (export) │  │ (fonts)  │                │
│   └──────────┘  └──────────┘  └──────────┘                │
│                                                             │
│   Tailwind CSS 4  ·  Vitest  ·  Playwright  ·  ESLint 9    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

✦ Getting Started

Prerequisites

  • Node.js >= 18
  • pnpm (recommended) or npm

Install & Run

# Clone
git clone https://github.com/12og3r/Pdfine.git && cd Pdfine

# Install dependencies
pnpm install

# Start dev server
pnpm dev

Open http://localhost:5173 — drop a PDF and start editing.

Live demo: 12og3r.github.io/Pdfine

Build

pnpm build         # Production build → dist/
pnpm preview       # Preview locally

Test

pnpm test           # Unit tests
pnpm test:watch     # Watch mode
npx playwright test # E2E (Chromium)

✦ Architecture

User types → hidden <textarea> → InputHandler → EditCommand
  → CommandHistory (undo/redo) → DocumentModel update
  → EventBus 'textChanged' → LayoutEngine reflow
  → RenderEngine re-render → Canvas update
Module overview
src/core/
├── EditorCore.ts          # Central orchestrator — wires all modules
├── parser/                # PDF parsing, text block extraction
├── model/                 # Document data model (outside React state)
├── layout/                # Text reflow, Greedy + Knuth-Plass line breaking
├── render/                # Canvas rendering pipeline, hit testing
├── editor/                # Input handling, IME, cursor, selection, undo/redo
├── font/                  # Font extraction, metrics, fallback chain
├── export/                # PDF export with white overlay + redraw strategy
├── infra/                 # EventBus, CoordinateTransformer, Logger
└── interfaces/            # I-prefixed contracts for all modules
Key design decisions
Decision Rationale
Document model lives outside React Real-time editing performance (100+ updates/sec)
Typed EventBus for module communication Decoupled modules, no circular dependencies
Hidden <textarea> for input capture Industry pattern (Google Docs, VS Code) for keyboard + IME
Canvas rendering (not DOM) Character-level positioning precision
White overlay export strategy Simplicity over PDF content stream editing

✦ Deploy

Pdfine is a fully static site — no backend, no env vars. Deploy anywhere:

                    ┌──────────────┐
   pnpm build ───▶ │    dist/     │ ───▶  Any static host
                    └──────────────┘
Platform How
Vercel vercel --prod
Netlify Connect repo or drag dist/
GitHub Pages Push dist/ to gh-pages
Cloudflare Pages Build: pnpm build, output: dist
Docker COPY dist/ /usr/share/nginx/html/

✦ Contributing

Contributions are welcome! Please open an issue first to discuss what you'd like to change.

# Development workflow
pnpm dev          # Start dev server
pnpm test:watch   # Run tests in watch mode
pnpm lint         # Lint before committing

✦ License

This project is licensed under the GNU General Public License v3.0 — see the LICENSE file for details.

You are free to use, modify, and distribute this software, provided that any derivative work is also distributed under the same license.



Built with care. Your PDFs stay yours.

Contributors

12og3rclaude

Issues