A client-side PDF signing application built with modern web technologies. Sign PDFs with complete privacy - all processing happens in your browser, no data leaves your device.
- Privacy-First: All PDF processing happens locally in your browser
- Multiple Annotation Types: Text, signatures, checkmarks, and dates
- WYSIWYG Editing: What you see is exactly what gets exported - pixel-perfect positioning
- Smooth Dragging: Real-time annotation movement with zero lag
- Cross-Platform: Works on desktop and mobile browsers
- Modern Export: Uses File System Access API with graceful fallbacks
This application solves common PDF annotation positioning issues:
- Exact positioning: Annotations appear in exported PDFs exactly where placed in the UI
- No position drift: Fixed the common PDF.js bug where exports don't match preview
- Coordinate transformation: Properly handles PDF (bottom-left origin) vs Canvas (top-left origin) systems
Smooth Dragging with CSS Transforms
- Uses CSS transforms for real-time visual feedback (eliminates React re-render lag)
- Updates position via
transform: translate()during drag, commits to state on mouseup - Result: Annotations follow cursor exactly with zero delay
Visual Refinements
- Minimal padding (1px 2px) and low opacity (0.1/0.2) for unobtrusive annotations
- Transitions disabled during drag for immediate response
Annotation Styling System
- Conditional styling: signature annotations get zero padding/font size to prevent oversized bounding boxes
- Order number labels positioned at bottom-left inside annotations with semi-transparent background
- CSS playground available at
?playground=truefor rapid style iteration using Playwright automation
-
PDF.js Coordinate Arrays
viewport.convertToPdfPoint(x, y)returns[x, y]array, NOT{x, y}object- Always destructure as arrays:
const [xPdf, yPdf] = viewport.convertToPdfPoint(x, y)
-
Viewport Configuration
- Always use
rotate: 0to prevent PDFs from rendering upside down - PDF.js automatically handles coordinate transformation - don't double-transform
- Always use
-
Anchor Point Differences
- Text: pdf-lib draws from baseline (not top-left)
- Images/Signatures: Draw from bottom-left corner
- Checkmarks: Custom paths, centered on click point
-
WYSIWYG Alignment
- UI rendering and PDF export use identical positioning logic
- Signatures/checkmarks centered with
translate(-50%, -50%)in UI - Export centers with
x - width/2, y - height/2for consistency
-
Performance-First Dragging
- Separate visual position (CSS transform) from logical position (React state)
- Batch position updates on mouseup instead of every mousemove
- Future: Consider pointer events for touch support, momentum/inertia effects
- Vite 7.1.4 - Build tool
- React 18 + TypeScript - UI framework
- PDF.js 5.4.149 - PDF rendering and coordinate mapping
- pdf-lib 1.17.1 - PDF modification and export
- signature_pad 5.1.0 - Digital signature capture
- @pdf-lib/fontkit - Font embedding support
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
# Preview production build
npm run previewThis application is designed to deploy to Cloudflare Pages:
- Connect your GitHub repository to Cloudflare Pages
- Build settings are auto-detected (Vite)
- Deploy automatically on git push
"Tried it out and downloaded the sample. Pretty nice. Better than Adobe imo."
β A Real Attorney (not legal advice)
- Content Security Policy headers configured
- No external API calls or data transmission
- All PDF processing happens client-side
- Privacy-focused architecture
MIT