{"id":47784299,"url":"https://github.com/lllyys/vreader","last_synced_at":"2026-06-06T18:01:09.936Z","repository":{"id":341863157,"uuid":"1171794967","full_name":"lllyys/vreader","owner":"lllyys","description":"iOS reader app for EPUB, PDF, TXT, and Markdown — with AI assistant, annotations, and full-text search. Built with Swift 6, SwiftUI, and SwiftData.","archived":false,"fork":false,"pushed_at":"2026-03-29T15:19:19.000Z","size":2449,"stargazers_count":3,"open_issues_count":8,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-29T17:39:19.326Z","etag":null,"topics":["ai","annotation","ebook","epub","highlights","ios","markdown","pdf","reader","search","swift","swiftdata","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lllyys.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-03T16:06:38.000Z","updated_at":"2026-03-29T15:19:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lllyys/vreader","commit_stats":null,"previous_names":["lllyys/vreader"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/lllyys/vreader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lllyys%2Fvreader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lllyys%2Fvreader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lllyys%2Fvreader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lllyys%2Fvreader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lllyys","download_url":"https://codeload.github.com/lllyys/vreader/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lllyys%2Fvreader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31356396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T08:03:20.796Z","status":"ssl_error","status_checked_at":"2026-04-03T08:00:37.834Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","annotation","ebook","epub","highlights","ios","markdown","pdf","reader","search","swift","swiftdata","swiftui"],"created_at":"2026-04-03T14:10:13.374Z","updated_at":"2026-04-03T14:10:14.071Z","avatar_url":"https://github.com/lllyys.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VReader\n\n**Built entirely by AI — coded, tested, and debugged by AI agents. Human-directed.**\n\nAn iOS reader for EPUB, AZW3/MOBI (Kindle), PDF, TXT, and Markdown — built entirely by AI coding agents, with Swift 6, SwiftUI, and SwiftData.\n\n## About\n\nVReader is a modern reading app designed for iPhone and iPad, built entirely by AI coding agents (Claude Code + Codex CLI) with human direction on requirements and testing. It supports EPUB, AZW3/MOBI (Kindle), PDF, TXT, and Markdown with annotations, full-text search, AI assistant, TTS, book source scraping, and WebDAV backup.\n\n## Features\n\n### Reading\n\n- **Multi-format** — EPUB, AZW3/MOBI (Kindle), PDF, TXT, Markdown in a single app\n- **AZW3/MOBI** — Kindle books via [Foliate-js](https://github.com/johnfactotum/foliate-js) engine (DRM-free only)\n- **Dual-mode engine** — Native (UIKit bridges) + Unified (TextKit 2 reflow) rendering\n- **Reading position** — Auto-saves scroll position, survives app kills and relaunches\n- **CJK encoding** — Auto-detect GBK, Big5, Shift-JIS, EUC-KR (8KB sample-based)\n- **Large file support** — Chunked UITableView for TXT files \u003e500K characters\n- **Paginated mode** — CSS columns (EPUB), TextKit containers (TXT/MD), PDFKit pages\n- **Page turn animations** — Slide, cover-flip, or instant\n- **Auto page turning** — Timer-based advancement with configurable interval\n- **Configurable tap zones** — Left/center/right zones mapped to customizable actions\n\n### Annotations\n\n- **Bookmarks, highlights, notes** — Full CRUD for TXT/MD/PDF/EPUB; AZW3 highlights in progress\n- **EPUB highlights** — CSS Highlight API with JS bridge + buffered delivery\n- **AZW3 highlights** — SVG overlay via Foliate-js overlayer + CFI anchoring\n- **PDF highlights** — PDFAnnotation-based with selection detection\n- **TXT/MD highlights** — NSAttributedString with persistent rendering\n- **Export/import** — Markdown + JSON export, VReader JSON round-trip import\n\n### Search \u0026 Navigation\n\n- **Full-text search** — SQLite FTS5 with CJK tokenization, persistent index\n- **Reading progress bar** — Draggable scrubber (continuous, page-based, chapter-based)\n- **Table of contents** — EPUB nav/NCX, PDF outline, TXT auto-detection (25 Legado rules), MD headings\n- **Dictionary** — System dictionary lookup + AI translation on text selection\n\n### AI\n\n- **Summarization** — Section and chapter summaries via OpenAI-compatible API\n- **Chat** — Multi-turn conversation with book context\n- **Translation** — Bilingual view (9 languages)\n- **General chat** — AI chat without book context\n\n### Library\n\n- **Grid/list view** — Persistent sort order and view mode\n- **Collections** — Tags, series, custom groups\n- **Custom covers** — Set from photo library\n- **Context menu** — Info, share, set cover, delete\n- **OPDS catalog** — Browse and download from OPDS 1.2 feeds\n- **Book sources** — Legado-compatible rule engine for web novel scraping\n\n### Text Processing\n\n- **TTS** — System (AVSpeechSynthesizer) + cloud HTTP TTS with playback controls\n- **TTS sentence highlight** — NLTokenizer-based sentence detection synced to speech position\n- **TTS auto-scroll** — Text view follows speech position in real-time\n- **Simp/Trad Chinese** — Toggle conversion via ICU (live re-apply without reloading)\n- **Content replacement** — Regex rules for text cleanup (live re-apply via source text storage)\n- **Reading time tracking** — Per-book session stats and speed calculations\n\n### Sync \u0026 Backup\n\n- **iCloud Sync** (foundation) — CloudKit sync engine, record mapper (8 types), device identity, change tokens, durable tombstones, settings bridge (NSUbiquitousKeyValueStore)\n- **WebDAV backup** — Archive to any WebDAV server (Nutstore compatible)\n- **Per-book settings** — Font, theme, spacing overrides per book (JSON-persisted)\n- **Theme backgrounds** — Custom background images via PhotosPicker with per-theme opacity\n\n## Tech Stack\n\n| Component   | Technology                                                                                      |\n| ----------- | ----------------------------------------------------------------------------------------------- |\n| UI          | SwiftUI                                                                                         |\n| Persistence | SwiftData (SchemaV4)                                                                            |\n| EPUB        | WKWebView bridge with CSS theme injection + JS highlight API                                    |\n| AZW3/MOBI   | [Foliate-js](https://github.com/johnfactotum/foliate-js) in WKWebView (IIFE bundle via esbuild) |\n| PDF         | PDFKit + PDFAnnotation for highlights                                                           |\n| TXT         | TextKit 1 (UITextView) + chunked UITableView                                                    |\n| Markdown    | NSAttributedString rendering via MDParser                                                       |\n| Search      | SQLite FTS5 with CJK tokenization                                                               |\n| AI          | OpenAI-compatible API (summarize, chat, translate)                                              |\n| TTS         | AVSpeechSynthesizer + HTTP cloud TTS                                                            |\n| Backup      | WebDAV client + iCloud Sync foundation (CloudKit)                                               |\n| Encoding    | ICU + heuristic detection (UTF-8/GBK/Big5/Shift-JIS)                                            |\n| Concurrency | Swift 6 strict concurrency                                                                      |\n\n## Requirements\n\n- iOS 17.0+\n- Xcode 16+\n- [XcodeGen](https://github.com/yonaskolb/XcodeGen)\n\n## Getting Started\n\n```bash\n# Generate the Xcode project\nxcodegen generate\n\n# Open in Xcode\nopen vreader.xcodeproj\n```\n\nThen select a simulator or device and run.\n\n## Architecture\n\nSee [`docs/architecture.md`](docs/architecture.md) for the full architecture document.\n\n```\nvreader/\n├── App/                 # App entry point, SwiftData schema init\n├── Models/              # SwiftData models, DocumentFingerprint, Locator\n├── ViewModels/          # Library and per-format reader view models\n├── Views/\n│   ├── Reader/          # Reader container, format bridges, chrome overlay\n│   ├── Bookmarks/       # BookmarkListView, TOCListView\n│   ├── Annotations/     # HighlightListView, AnnotationListView\n│   └── Settings/        # ReaderSettingsPanel, AI/TTS/WebDAV settings\n├── Services/\n│   ├── TXT/, EPUB/, MD/ # Format-specific parsing and loading\n│   ├── Foliate/         # AZW3/MOBI via Foliate-js (scheme handler, adapters, JS bundle)\n│   ├── Search/          # FTS5 indexing, text extraction\n│   ├── AI/, TTS/        # AI service, TTS providers\n│   ├── Backup/          # WebDAV client, BackupProvider\n│   ├── Sync/            # iCloud sync engine, CloudKit mapper, tombstones\n│   ├── TextMapping/     # Simp/Trad, replacement rules\n│   └── Locator/         # Reading position (Readium-inspired)\nvreaderTests/            # Unit tests (3200+ test cases)\nvreaderUITests/          # UI tests (XCUITest)\n```\n\n### Key Design Decisions\n\n- **Foliate-js for AZW3/MOBI** — Kindle books are parsed and rendered by [Foliate-js](https://github.com/johnfactotum/foliate-js) running in WKWebView. The entire library is bundled into a single 278KB IIFE via esbuild (WKWebView blocks ES modules on custom schemes). A `WKURLSchemeHandler` serves the JS bundle and book files from a single origin to avoid CORS issues.\n- **Three-renderer architecture** — Each format uses the best tool: Foliate-js in WKWebView (AZW3/MOBI), custom WKWebView bridge (EPUB), PDFKit (PDF), UITextView (TXT/MD). Shared services (Locator, Highlight, Search, TTS, Position) work across all renderers.\n- **CFI-based positions for EPUB/AZW3** — Foliate-js generates EPUB CFI strings for both EPUB and MOBI (fake CFIs for MOBI). These are stored in `Locator.cfi` as the authoritative position, enabling unified persistence and highlight anchoring.\n- **TextKit 1 for TXT rendering** — UITextView with `NSLayoutManager` for reliable offset-to-scroll mapping. TextKit 2 has better performance but lacks the `charOffset ↔ scrollOffset` APIs needed for position persistence.\n- **Chunked rendering for large files** — Files over 500K UTF-16 code units use a UITableView where each cell renders one \\~16K chunk. Only visible cells build attributed strings (LRU cache of 20 chunks).\n- **Two-phase scroll restore** — Position restore uses a Phase 1 (t+0.15s) + Phase 2 (t+0.8s) pattern to handle TextKit 1 compatibility mode relayout storms that reset `contentOffset`.\n- **`@State` for one-shot values** — Rapidly-mutating `@Observable` properties are never read in SwiftUI body to avoid observation feedback loops. Position restore uses `@State` captured once after `open()`.\n- **Background task protection** — `UIApplication.beginBackgroundTask` wraps all critical saves (`close()`, `onBackground()`) to prevent data loss when iOS suspends the process.\n\n## AI-Powered Development\n\nAll code, tests, bug fixes, and documentation are produced by AI coding agents. The human role is directing requirements, reporting bugs, and verifying on device.\n\n### Tools\n\n| Tool                                          | Role                                                                |\n| --------------------------------------------- | ------------------------------------------------------------------- |\n| [Claude Code](https://claude.com/claude-code) | Primary coding agent — implementation, editing, code review, fixes  |\n| [Codex CLI](https://github.com/openai/codex)  | Architecture review, auditing, autonomous implementation in sandbox |\n\n### Workflow\n\nThe development process follows a gated, multi-agent pipeline:\n\n1. **Plan** — Features are designed as detailed implementation plans with work items, acceptance criteria, and test requirements (`docs/codex-plans/`)\n2. **Review** — Plans go through multi-round architecture review via Codex (consistency, completeness, feasibility, ambiguity, risk)\n3. **Implement** — Work items are implemented by the implementer agent following TDD (RED-GREEN-REFACTOR)\n4. **Audit** — Code is audited across 9 dimensions (correctness, security, concurrency, performance, etc.)\n5. **Fix** — Audit findings are fixed and verified in iterative loops until clean\n6. **Commit** — Changes are committed only on explicit request after passing all gates\n\n### Agent Rules\n\nShared rules for all AI agents live in ``:\n\n- **Test-first is mandatory** — Write a failing test before implementing any new behavior\n- **Research before building** — Search for established patterns and proven solutions before inventing\n- **Edge cases are not optional** — Brainstorm and test: empty input, null values, Unicode/CJK, concurrent access, network failures\n- **Keep files under \\~300 lines** — Split proactively to maintain readability\n- **Keep diffs focused** — No drive-by refactors; only change what's needed\n\n### Configuration\n\n- `.claude/rules/` — Rule files for TDD, UI consistency, design tokens, keyboard shortcuts, version bumping\n- `.claude/skills/` — Custom skill definitions (plan-audit, etc.)\n- `CLAUDE.md` — Claude Code project instructions\n- `AGENTS.md` — Shared instructions for all AI coding agents\n\n## Status\n\nActive development. See [features](docs/features.md) (38 done) and [bugs](docs/bugs.md) (102 fixed) for current state.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flllyys%2Fvreader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flllyys%2Fvreader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flllyys%2Fvreader/lists"}