Files
epub-read/docs/superpowers/specs/2026-05-13-epub-reader-design.md

163 lines
5.5 KiB
Markdown
Raw Permalink Normal View History

# ePub Reader — Design Document
## Overview
A lightweight ePub reader desktop application built with Rust + egui, compiled as a single Windows executable (x86_64-pc-windows-gnu / MSYS2+MinGW). No console window. Built-in Chinese font support. Kindle-like reading experience with medium feature set.
## Tech Stack
| Layer | Choice |
|---|---|
| GUI Framework | `eframe` (egui official framework) |
| Rendering Backend | `wgpu` |
| ePub Parsing | `epub-rs` |
| Font | Bundled Noto Sans SC (or similar open-source Chinese font) |
| Build Target | `x86_64-pc-windows-gnu` |
| Binary | Single `.exe`, `#![windows_subsystem = "windows"]` |
## Core Data Model
```rust
struct AppState {
book: Option<Book>,
current_section: usize,
current_page: usize,
settings: Settings,
bookmarks: Vec<Bookmark>,
sidebar_open: bool,
}
struct Book {
title: String,
author: String,
cover: Option<Vec<u8>>,
sections: Vec<Section>,
toc: Vec<TocEntry>,
}
struct Section {
title: String,
content: String, // plain text (HTML tags stripped)
pages: Vec<usize>, // character offsets for page boundaries
}
struct Settings {
font_size: f32, // default 20.0
theme: Theme,
}
enum Theme { Light, Dark }
struct Bookmark {
section: usize,
page: usize,
label: String,
timestamp: i64,
}
struct TocEntry {
label: String,
section: usize,
children: Vec<TocEntry>,
}
```
## Architecture
```
┌──────────────────────────────────────────┐
│ eframe::App │
│ ┌──────────┐ ┌───────────────────────┐ │
│ │ WelcomePg │ │ ReadingView │ │
│ │ (no book) │ │ ├─ TopToolbar │ │
│ │ ──────── │ │ ├─ Sidebar (TOC) │ │
│ │ open btn │ │ ├─ TextArea │ │
│ │ recents │ │ └─ BottomProgressBar │ │
│ └──────────┘ └───────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ AppState │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────┘
```
## UI Layout
### Welcome Screen (no book open)
- Centered "Open ePub File" button
- Recently opened books list (read from settings file)
### Reading Screen (Kindle-like)
- **Top toolbar**: back button, book title, font size controls, menu, bookmark toggle, theme toggle
- **Left sidebar** (collapsible): table of contents tree
- **Center**: text content area with pagination
- Click left 30% → prev page, right 30% → next page, center 40% → toggle toolbar visibility
- Keyboard: ← → for prev/next page
- **Bottom bar**: current chapter name, progress slider, page number indicator
## Features (Medium Scope)
### Core
1. Open `.epub` file via native file dialog
2. Parse ePub (OPF manifest, NCX/TOC, Spine)
3. Render chapter content with pagination
4. Next/previous page navigation (click & keyboard)
5. Table of contents sidebar with chapter navigation
6. Remember last reading position (bookmark per file)
### Settings & Display
7. Font size adjustment (A⁺/A⁻)
8. Light/Dark theme toggle
9. Chinese font support (bundled Noto Sans SC)
### Bookmarks
10. Add/remove bookmarks at current page
11. Bookmark list view
### Persistence
12. `settings.json` saves: font_size, theme, recent files, reading positions, bookmarks
## Data Flow
1. User clicks "Open" → native file dialog → select `.epub`
2. `EpubLoader` reads zip, extracts OPF metadata, reads spine order, parses NCX for TOC
3. For each spine item: extract HTML content, strip tags → plain text stored in `Section.content`
4. On section load: calculate pagination based on current font_size + panel width → store page offsets
5. On page change: slice `Section.content[pages[current_page]..pages[current_page+1]]` → render to egui `Label`
6. On font_size change: recalculate all pagination for current section
7. On theme toggle: switch `egui::Style` between light/dark visuals
## Pagination Algorithm
```
fn paginate(text: &str, font_size: f32, panel_width: f32) -> Vec<usize>
chars_per_line = floor(panel_width / (font_size * 0.6))
lines_per_page = floor(panel_height / (font_size * 1.5))
chars_per_page = chars_per_line * lines_per_page
Iterate text, split at chars_per_page boundaries (prefer word/char boundaries)
```
## File Storage
- `settings.json` (next to exe OR in standard config dir)
- font_size, theme
- recent_files: Vec<{path, title}>
- reading_positions: HashMap<path, {section, page}>
- bookmarks: HashMap<path, Vec<Bookmark>>
- Last window size/position
## Error Handling
- ePub parsing failure → show error dialog with message
- File not found (recent list) → remove from list silently
- Font loading failure → fall back to system monospace
- Settings file corruption → reset to defaults, log warning
## Out of Scope (v1)
- Text search within book
- Highlighting / annotations
- Notes/export
- TTS
- Epub with complex CSS styling / reflowable layout math
- DRM-protected ePubs