Chunkpad is a cross-platform desktop application built with Electron and React that processes documents entirely client-side. It follows a modular architecture with clear separation between document parsing, content chunking, editing, and export functionality. The application runs as a native desktop app on macOS, Windows, and Linux while maintaining the same core functionality as the web version.
┌─────────────────────────────────────────────────────────────┐
│ Main Process (Node.js) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Window Management │ │
│ │ Application Menu │ │
│ │ File System Operations (Native Dialogs) │ │
│ │ IPC Handlers │ │
│ │ Platform-Specific Features (Dock, Taskbar, etc.) │ │
│ └──────────────────┬───────────────────────────────────┘ │
└─────────────────────┼───────────────────────────────────────┘
│ IPC (Inter-Process Communication)
↓
┌─────────────────────────────────────────────────────────────┐
│ Preload Script (Bridge) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Secure IPC Bridge │ │
│ │ Context Isolation │ │
│ │ Exposed Electron APIs │ │
│ └──────────────────┬───────────────────────────────────┘ │
└─────────────────────┼───────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ Renderer Process (React + Browser APIs) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ User Interface Layer │ │
│ │ (React Components + TipTap Editor + shadcn/ui) │ │
│ └──────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌──────────────────┴───────────────────────────────────┐ │
│ │ Application State │ │
│ │ (React State + Project File Persistence) │ │
│ └──────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌──────────────────┴───────────────────────────────────┐ │
│ │ Core Services Layer │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │ │
│ │ │ Document │ │ Chunking │ │ Export │ │ │
│ │ │ Parsers │ │ Engine │ │ Formatters│ │ │
│ │ └──────────────┘ └──────────────┘ └───────────┘ │ │
│ └──────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌──────────────────┴───────────────────────────────────┐ │
│ │ External Libraries │ │
│ │ pdfjs-dist | mammoth | jszip | tiktoken | turndown │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
The web version maintains the same core architecture but runs entirely in the browser without Electron:
┌─────────────────────────────────────────────────────────────┐
│ User Interface Layer │
│ (React Components + TipTap Editor + shadcn/ui) │
└────────────────┬────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ Application State │
│ (React State + LocalStorage for Metadata) │
└────────────────┬────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ Core Services Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ Document │ │ Chunking │ │ Export │ │
│ │ Parsers │ │ Engine │ │ Formatters │ │
│ └──────────────┘ └──────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ External Libraries │
│ pdfjs-dist | mammoth | jszip | tiktoken | turndown │
└─────────────────────────────────────────────────────────────┘
chunklist/
├── electron/ # Electron-specific code
│ ├── main.ts # Main process (window management, IPC)
│ ├── preload.ts # Preload script (secure IPC bridge)
│ └── types.ts # IPC type definitions
│
├── src/ # React application (shared with web version)
│ ├── components/ # React UI components
│ │ ├── ui/ # shadcn/ui primitives
│ │ ├── AddChunkButton.tsx
│ │ ├── ChunkList.tsx
│ │ ├── DocumentMetadataDialog.tsx
│ │ ├── ExportDialog.tsx
│ │ ├── FileList.tsx
│ │ ├── FileUploader.tsx
│ │ ├── GlobalMetadataDialog.tsx
│ │ ├── KeyboardShortcutsDialog.tsx # Desktop: Keyboard shortcuts help
│ │ ├── LoadingOverlay.tsx # Desktop: Loading indicators
│ │ ├── Logo.tsx
│ │ ├── MarkdownEditor.tsx
│ │ ├── MenuBar.tsx
│ │ ├── NavLink.tsx
│ │ └── SettingsDialog.tsx
│ │
│ ├── lib/ # Core business logic
│ │ ├── chunking.ts
│ │ ├── docxParser.ts
│ │ ├── frontMatter.ts
│ │ ├── htmlToMarkdown.ts
│ │ ├── pdfParser.ts
│ │ ├── pptxParser.ts
│ │ ├── project.ts # Desktop: Project file serialization
│ │ └── utils.ts
│ │
│ ├── pages/ # Page components
│ │ ├── Index.tsx # Main application page
│ │ └── NotFound.tsx
│ │
│ ├── types/ # TypeScript definitions
│ │ └── index.ts # Includes ProjectData interface
│ │
│ ├── hooks/ # Custom React hooks
│ │ ├── use-mobile.tsx
│ │ └── use-toast.ts
│ │
│ ├── data/ # Static data
│ │ └── mockData.ts
│ │
│ ├── assets/ # Static assets
│ │ └── *.svg, *.png
│ │
│ ├── App.tsx # Root component
│ ├── index.css # Global styles + design system
│ └── main.tsx # Application entry point
│
├── build/ # Electron builder configuration
│ └── icons/ # App icons for different platforms
│
├── package.json # Dependencies and build scripts
├── vite.config.ts # Vite + Electron configuration
├── tailwind.config.ts # Tailwind CSS configuration
└── tsconfig.json # TypeScript configuration
Technology: PDF.js (Mozilla's PDF rendering library)
Process:
- Loads PDF as Uint8Array
- Iterates through each page
- Extracts text content with positioning data
- Analyzes Y-coordinates to detect paragraph breaks
- Groups text into semantic paragraphs
- Outputs structured HTML with
<div data-source="pdf" data-page="N">wrappers
Key Features:
- Paragraph detection based on vertical spacing
- Font size analysis for potential header detection
- Preserves page structure
- Handles multi-column layouts
Output Format:
<div data-source="pdf" data-page="1">
<h2>Page 1</h2>
<p>First paragraph content...</p>
<p>Second paragraph content...</p>
</div>Technology: Mammoth.js
Process:
- Receives ArrayBuffer from file upload
- Mammoth converts DOCX to HTML
- Preserves document structure (headings, lists, tables)
- Returns semantic HTML
Key Features:
- Maintains heading hierarchy
- Preserves bold, italic, and underline formatting
- Converts tables to HTML
<table>elements - Handles lists with proper nesting
Output Format: Semantic HTML with proper tags (h1-h6, p, ul, ol, table)
Technology: JSZip (for extracting PPTX structure)
Process:
- Unzips PPTX (OpenXML format)
- Iterates through
ppt/slides/slideN.xmlfiles - Parses XML using DOMParser
- Extracts slide titles from placeholder elements
- Extracts paragraphs from text body elements
- Filters out duplicate title text from body content
Key Features:
- Namespace-aware XML parsing
- Title detection from presentation placeholders
- Paragraph-level text extraction
- Handles multiple text elements per slide
Output Format:
<div data-source="pptx" data-page="1">
<h2>Slide Title</h2>
<p>Bullet point 1</p>
<p>Bullet point 2</p>
</div>The chunking engine uses a multi-strategy architecture that allows users to choose from different chunking algorithms optimized for different document types and use cases. The system is built on a pluggable strategy pattern with a normalized document representation.
Key Components:
-
Document Normalization (
src/lib/document/parser.ts)- Converts HTML from parsers into normalized
DocumentBlock[]structure - Preserves structure, metadata, and formatting
- Enables structure-aware chunking algorithms
- Converts HTML from parsers into normalized
-
Strategy System (
src/lib/chunking/)- Strategy Interface: Defines contract for all chunking strategies
- Strategy Registry: Map-based registry for strategy lookup
- Strategy Implementations: 4 production-ready strategies
-
Legacy Compatibility (
src/lib/chunking.ts)- Maintains backward compatibility with original
chunkDocument()function - Delegates to fixed-size strategy internally
- Maintains backward compatibility with original
1. Fixed-Size Strategy (strategies/fixed-size.ts)
- Token-based chunking with configurable size and overlap
- Respects HTML block boundaries
- Default strategy for backward compatibility
- Best for: General purpose, unstructured documents
2. Heading-Aware Strategy (strategies/heading-aware.ts)
- Groups content under headings, preserving document hierarchy
- Creates chunks that start at heading boundaries
- Includes
sectionPathmetadata for hierarchical filtering - Best for: Structured documents (manuals, reports, technical docs)
3. Paragraph-Aware Strategy (strategies/paragraph-aware.ts)
- Recursive splitting: paragraph → sentence → token level
- Maintains paragraph coherence
- Never splits mid-sentence
- Best for: Narrative content (blog posts, articles, stories)
4. Sliding Window Strategy (strategies/sliding-window.ts)
- Creates overlapping chunks with configurable window and overlap
- Maximum context preservation
- Preserves word/sentence boundaries
- Best for: Technical documents where context spanning boundaries is critical
-
countTokens(text: string): number(utils.ts)- Uses tiktoken with GPT-3.5-turbo encoding
- Returns accurate token count for AI model compatibility
- Shared utility used by all strategies
-
chunkDocument(content, targetSize, overlapSize, metadata): Chunk[](legacy)- Maintained for backward compatibility
- Delegates to fixed-size strategy
- Converts HTML → DocumentStructure → chunks
-
Strategy Interface (
strategy.ts)interface ChunkingStrategy { id: string; name: string; description: string; defaultOptions: ChunkingOptions; chunk(structure: DocumentStructure, options: ChunkingOptions, globalMetadata: GlobalMetadata): Chunk[]; validateOptions?(options: ChunkingOptions): boolean; }
-
formatChunkWithFrontMatter(chunk, metadata): string- Adds YAML front matter to chunk content
- Merges global and chunk-specific metadata
- Includes strategy metadata in exports
Input: HTML Content from Parser
↓
HTML → DocumentStructure Conversion
↓
Select Strategy (from fileChunkingConfig or default)
↓
Strategy.chunk(DocumentStructure, options, metadata)
↓
Strategy-specific Algorithm:
├─ Fixed-Size: Group blocks until maxTokens
├─ Heading-Aware: Group under headings, preserve hierarchy
├─ Paragraph-Aware: Group paragraphs, recursive fallback
└─ Sliding Window: Overlapping windows with boundaries
↓
Output: Array of Chunk objects with strategy metadata
interface Chunk {
id: string; // Unique identifier
title: string; // Extracted from heading or auto-generated
preview: string; // First 100 chars of text content
content: string; // Full HTML content
tokens?: number; // Token count
metadata?: {
// User-defined metadata
topic?: string;
category?: string;
"domain-area"?: string;
// Strategy metadata (new in v0.2.0+)
strategy?: string; // Strategy ID used
strategyOptions?: Record<string, any>; // Options used
sectionPath?: string[]; // Heading hierarchy (heading-aware)
sourceFile?: string; // Source file name
page?: number; // Page number (PDF)
slide?: number; // Slide number (PPTX)
[key: string]: string | string[] | number | undefined;
};
}Each file in a project can have its own chunking strategy and options:
interface ProjectData {
// ... existing fields
fileChunkingConfig?: Record<string, {
strategy: string; // Strategy ID
options: Record<string, any>; // Strategy-specific options
}>;
}Configuration Flow:
- User selects file
- Opens Settings dialog
- Chooses strategy from dropdown
- Configures strategy-specific options
- Document is re-chunked with new strategy
- Configuration saved in
fileChunkingConfig
Common Options (all strategies):
maxTokens/windowSize: Maximum tokens per chunk (default: 1000)overlapTokens/overlapSize: Overlap between chunks (default: 150)
Strategy-Specific Options:
- Heading-Aware:
subChunkingStrategy("paragraph" | "sentence"),minChunkTokens - Paragraph-Aware:
minParagraphsPerChunk,maxParagraphsPerChunk - Sliding Window:
preserveWordBoundaries,preserveSentenceBoundaries
Migration Strategy:
- Old projects without
fileChunkingConfigautomatically migrate chunkSize/overlapSize→fileChunkingConfigwith fixed-size strategy- All existing chunks remain valid
- Legacy
chunkDocument()function still works
Default Behavior:
- New files default to fixed-size strategy (same as before)
- Existing projects continue to work without changes
- Users can optionally upgrade to new strategies
Technology: TipTap (ProseMirror-based rich text editor)
Extensions Enabled:
- StarterKit (basic formatting)
- Table, TableRow, TableCell, TableHeader
- Image
- Link
- Subscript, Superscript
- Text styling
Features:
- Real-time HTML editing
- Markdown-compatible output
- Toolbar with formatting buttons
- Front matter parsing and preservation
- Auto-save on content change
Two Levels:
-
Global Metadata (
GlobalMetadataDialog.tsx)- Applied to all chunks in a document
- Stored per-file in application state
- Used for document-wide classification
-
Chunk Metadata (
DocumentMetadataDialog.tsx)- Applied to individual chunks
- Overrides global metadata
- Useful for fine-grained categorization
Front Matter Integration (src/lib/frontMatter.ts):
- Parses YAML front matter from markdown
- Extracts metadata key-value pairs
- Preserves front matter during editing
- Merges with global metadata on export
Technology: Turndown.js
Configuration:
{
headingStyle: "atx", // # Heading style
hr: "---", // Horizontal rules
bulletListMarker: "-", // List markers
codeBlockStyle: "fenced", // ``` code blocks
emDelimiter: "*", // *italic*
strongDelimiter: "**" // **bold**
}Functions:
-
htmlToMarkdown(html: string): string- Converts HTML to clean markdown
- Removes excessive whitespace
- Handles errors gracefully with fallback
-
stripHtmlTags(html: string): string- Extracts plain text from HTML
- Uses DOM parsing for accuracy
- Collapses whitespace intelligently
1. JSON Export
[
{
"id": "chunk-1-1234567890",
"title": "Chunk 1: Introduction",
"preview": "First 100 characters...",
"content": "<p>Full HTML content...</p>",
"tokens": 856,
"metadata": {
"topic": "Introduction",
"category": "Documentation"
}
}
]2. Markdown Export
---
topic: Introduction
category: Documentation
---
# Chunk 1: Introduction
Paragraph content converted to clean markdown...
---
[Next chunk with same format]3. Plain Text Export
Chunk 1: Introduction
======================
Plain text extracted from HTML with proper spacing...
[Next chunk with same format]
Export Modes:
- Single File: All chunks combined into one file
- Multiple Files: One file per chunk with optional prefix and separator
// Main page state (src/pages/Index.tsx)
{
files: DocFile[]; // Loaded documents
selectedFileId: string | null; // Currently selected file
selectedChunkId: string | null; // Currently selected chunk
chunksData: Record<string, Chunk[]>; // Chunks per file
chunkSize: number; // Target chunk size
overlapSize: number; // Chunk overlap
globalMetadata: Record<string, GlobalMetadata>; // Metadata per file
sidebarCollapsed: boolean; // UI state
editingFileName: boolean; // UI state
editingFileNameValue: string; // UI state
}User Action
↓
Event Handler (onClick, onChange, etc.)
↓
State Update (setState)
↓
Re-render affected components
↓
Update derived values (computed chunks, filtered lists)
No Server Required:
- All processing happens client-side
- No data leaves the browser
- Files are processed in memory
- State is ephemeral (resets on page reload)
Future Enhancement Options:
- LocalStorage for draft persistence
- IndexedDB for large document caching
- Backend integration for collaboration features
Color System: HSL-based semantic tokens
colors: {
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: "hsl(var(--primary))",
secondary: "hsl(var(--secondary))",
muted: "hsl(var(--muted))",
accent: "hsl(var(--accent))",
// ... and more
}Light Mode:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
/* ... */
}Dark Mode:
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... */
}shadcn/ui Components Used:
- Dialog, Sheet (modals)
- Button, Input, Textarea, Checkbox, Radio
- Select, Slider (form controls)
- Card, Badge (content containers)
- Toast (notifications)
- Accordion, Collapsible (disclosure)
- Scroll Area (custom scrollbars)
-
Loading States:
- Progress indicators for file parsing (20% → 60% → 90% → 100%)
- Loading overlays for async operations
- File size warnings for large files (>50MB)
-
Memory Management:
- Files processed in memory (renderer process)
- Large file warnings (>50MB)
- Efficient chunk rendering with search/filter
-
Startup Performance:
- Fast window creation
- Lazy loading of heavy dependencies
- Optimized bundle size with Vite
-
File Operations:
- Native dialogs (non-blocking)
- Async file reading/writing
- Progress feedback for long operations
-
Lazy Loading:
- Components loaded on-demand
- Large libraries (PDF.js) loaded asynchronously
-
Memoization:
- Expensive computations cached with
useMemo - Event handlers stabilized with
useCallback
- Expensive computations cached with
-
Virtual Scrolling (Future Enhancement):
- For documents with 100+ chunks
- Would use
react-windowor similar
-
Web Workers (Future Enhancement):
- Offload parsing to background thread
- Prevent UI blocking on large files
Desktop App Requirements:
- macOS: macOS 10.13 (High Sierra) or later
- Windows: Windows 10 or later
- Linux: Modern distributions with GTK3 or later
Web Version Requirements:
- Modern browsers with ES6+ support
- Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
Key APIs Used:
- File API (for file uploads)
- ArrayBuffer (for binary file handling)
- DOMParser (for XML parsing)
- Blob/URL APIs (for downloads)
- Electron APIs (desktop: native dialogs, file system)
Electron Security Model:
- Context isolation enabled (prevents renderer from accessing Node.js)
- Node integration disabled in renderer process
- Sandbox mode disabled (required for file operations)
- Preload script provides secure API surface
- All file operations go through main process
Benefits:
- No data transmitted to servers
- Privacy-preserving by design
- No authentication required
- No data storage on external systems
- Files never leave user's device
- Suitable for sensitive documents
IPC Security:
- All IPC channels explicitly defined
- No arbitrary code execution from renderer
- Type-safe IPC communication via preload bridge
Client-Side Processing:
- No data transmitted to servers
- Privacy-preserving by design
- No authentication required
- No data storage on external systems
- All processing in browser memory
- Files never leave user's device
- Suitable for sensitive documents
Regular Updates:
- Dependencies updated via
npm audit - No known critical vulnerabilities
- All libraries from trusted sources (npm)
- Electron security best practices followed
-
Unit Tests:
- Parsing functions (PDF, DOCX, PPTX)
- Chunking algorithm
- HTML-to-Markdown conversion
- Token counting accuracy
-
Integration Tests:
- File upload → Parse → Chunk flow
- Edit → Export flow
- Metadata application
-
E2E Tests:
- Full user workflows
- Cross-browser compatibility
Suggested Tools:
- Vitest (unit tests)
- React Testing Library (component tests)
- Playwright (E2E tests)
IPC (Inter-Process Communication):
- Main Process → Renderer Process: Uses
webContents.send()for menu actions - Renderer Process → Main Process: Uses
ipcRenderer.invoke()for async operations - Preload Script: Acts as secure bridge, exposes
window.electronAPI
IPC Channels:
file:open-dialog- Open file pickerfile:save-dialog- Save file pickerfile:open-directory- Directory pickerfile:save-content- Write file contentproject:save- Save project fileproject:load- Load project filemenu:*- Menu action eventsfile:open-document- Open document from command linefile:open-project- Open project from command line
Security Model:
- Context isolation enabled
- Node integration disabled in renderer
- All file operations go through main process
- Preload script provides secure API surface
File Operations:
- File reading: Main process reads files, sends ArrayBuffer to renderer
- File writing: Renderer sends content to main process, main process writes
- Native dialogs: All file dialogs use Electron's native APIs
macOS:
- Dock menu with quick actions
- Native title bar integration
open-fileevent handling- App menu in menu bar
Windows:
- Taskbar integration
- App user model ID for notifications
- NSIS installer support
- Jump lists (future enhancement)
Linux:
- AppImage, .deb, .rpm packages
- Desktop file integration
- System tray support (future enhancement)
Build Process:
Source Code
↓
Vite Build (Renderer)
↓
Electron Build (Main + Preload)
↓
electron-builder Package
↓
Platform-Specific Distributables
Distribution Formats:
- macOS:
.dmg(disk image),.zip(for direct distribution) - Windows:
.exe(NSIS installer),.zip(portable) - Linux:
.AppImage(portable),.deb(Debian/Ubuntu),.rpm(Fedora/RHEL)
No Backend Required:
- 100% client-side processing
- No server infrastructure needed
- Files never leave user's device
- Zero cloud costs
The web version can still be deployed to static hosting:
User's Browser
↓
CDN/Edge Network
↓
Static Files (HTML, JS, CSS)
↓
Client-Side Processing
Recommended Platforms:
- Vercel/Netlify - Git integration, preview deployments
- GitHub Pages - Free hosting for open source
- AWS S3 + CloudFront - Enterprise-grade hosting
Responsibilities:
- Window lifecycle management
- Application menu creation
- Native file dialogs
- IPC handlers for file operations
- Platform-specific features (dock menu, etc.)
- Command-line argument handling
- File association handling
Key Functions:
createWindow()- Creates and configures main windowcreateMenu()- Builds platform-specific menu barhandleFileOpen()- Processes files opened from command line or "Open With"
Responsibilities:
- Exposes secure IPC bridge to renderer
- Provides type-safe API surface
- Maintains context isolation
- Handles menu event forwarding
Exposed API (window.electronAPI):
- File operations (open, save, directory picker)
- Project operations (save, load)
- Window operations (minimize, maximize, close)
- Menu event listeners
- Platform information
Renderer Process (React)
↓ (calls window.electronAPI.openFile())
Preload Script
↓ (ipcRenderer.invoke('file:open-dialog'))
Main Process
↓ (dialog.showOpenDialog())
Native OS Dialog
↓ (user selects file)
Main Process
↓ (reads file, returns data)
Preload Script
↓ (returns Promise result)
Renderer Process
↓ (receives file data)
React Component
↓ (processes file)
-
Loading States:
- Progress indicators for file parsing
- Loading overlays for async operations
- File size warnings for large files
-
Memory Management:
- Files processed in memory (renderer process)
- Large file warnings (>50MB)
- Efficient chunk rendering
-
Startup Performance:
- Fast window creation
- Lazy loading of heavy dependencies
- Optimized bundle size
-
File Operations:
- Native dialogs (non-blocking)
- Async file reading/writing
- Progress feedback for long operations
-
Backend Integration (Optional):
- User accounts and cloud sync
- Collaboration features
- Document history tracking
- Multi-device synchronization
-
AI Integration:
- Automatic chunk summarization
- Keyword extraction
- Semantic similarity scoring
- Smart chunk merging/splitting
-
Vector Database Export:
- Direct export to Pinecone, Weaviate, etc.
- Automatic embedding generation
- Batch export with metadata
-
Real-time Collaboration (Future):
- Multiple users editing simultaneously
- WebSocket-based sync
- Operational transformation
-
Advanced Parsing:
- OCR for scanned PDFs
- Image extraction and analysis
- Table structure preservation
- Multi-language support
-
Desktop Enhancements:
- Auto-update functionality
- Recent files menu
- System tray integration
- Global keyboard shortcuts
This architecture is designed to be simple, maintainable, and extensible while providing robust document processing capabilities entirely client-side, with native desktop integration for an optimal user experience.