A cross-platform application for organizing, reading, and listening to webnovels directly on your device. Webnovel Reader turns TXT files, PDFs with selectable text, and manually pasted content into a local library, preserving chapters, preferences, and reading progress without requiring an account or a constant internet connection.
Built with Expo, React Native, and TypeScript, the project runs on Android, iOS, and the web from a single codebase.
Webnovel Reader is designed for readers who keep chapters in separate files or want to build a personal reading collection. The main workflow lets users:
- import one or multiple chapters;
- review titles and arrange the files;
- save the content as a new or existing webnovel;
- read with a customizable appearance;
- resume from the saved position or listen using the voices available on the device.
Structured data is stored in SQLite, while the full chapter content is kept as text files in the application's document directory. This separation avoids storing long texts in the database and keeps library and progress queries simple and efficient.
- Lists webnovels stored on the device.
- Displays chapter counts and the last chapter accessed.
- Provides a detail screen with chapters in reading order.
- Offers quick access to start or resume reading.
- Works offline after content has been imported.
- Select multiple TXT and PDF files.
- Sort selected files naturally and rearrange them manually before saving.
- Derive initial chapter titles from file names, with support for editing them.
- Extract text from digital PDFs on Android, iOS, and the web.
- Normalize imported text and count its words.
- Create chapters manually from pasted text.
- Create a new webnovel or add a manual chapter to an existing one.
- Identify chapters that could not be read before completing an import.
Scanned or image-only PDFs cannot be processed because the project does not currently include OCR. A PDF must contain extractable text.
- Paper, Sepia, and Night themes.
- Adjustable font size and line height.
- Brightness controls while reading.
- Navigation between previous and next chapters.
- Persistent scroll position and narration position.
- Automatic progress restoration when reopening a chapter.
- Text selection to choose where narration should begin.
- Text-to-speech powered by
expo-speechand the voices installed on the device. - Playback, pause, and approximate 10-second skip forward or backward controls.
- Adjustable speed, pitch, and voice.
- Automatic splitting of long chapters into sections supported by the TTS engine.
- Automatic continuation to the next chapter when narration finishes.
- Position persistence when pausing, leaving the reader, or sending the app to the background.
- Interface available in Brazilian Portuguese and English.
- Locally persisted reading, audio, and language preferences.
- Global reader theme selection.
- Integration with the system light or dark theme at the navigation layer.
| Technology | Role |
|---|---|
| Expo 54 / React Native 0.81 | Cross-platform application foundation |
| React 19 | Declarative user interface |
| TypeScript | Strict typing and contracts between modules |
| Expo Router | File-based routing and typed routes |
| Expo SQLite | Catalog, progress, and preference persistence |
| Expo File System | Chapter content storage and retrieval |
| Expo Document Picker | Local TXT and PDF file selection |
| PDF.js | PDF text extraction |
| Expo Speech | Text-to-speech chapter narration |
| Expo Brightness | Reader brightness controls |
| React Navigation | Stack and bottom-tab navigation |
The project uses a feature-first MVVM architecture blended with React Native and Expo Router conventions. The @/ alias points to src/. Route files remain in the root app/ directory and are thin adapters with no application logic. app.json explicitly configures this router root so the organizational src/app/ directory is never interpreted as routes.
Routes (app/) ──► Screens / Views (src/features/*/*.screen.tsx)
│
▼
Hooks / ViewModels
│
┌──────────┴──────────┐
▼ ▼
Feature model + API Infra capabilities
│ │
└──────────┬──────────┘
▼
Shared contracts and UI
The app/ directory uses Expo Router's file-based routing convention. Its files are intentionally small: they receive navigation requests and render a screen exported by the corresponding feature module.
| Route | Responsibility |
|---|---|
app/(tabs)/index.tsx |
Library |
app/(tabs)/import.tsx |
Chapter import |
app/(tabs)/settings.tsx |
Global preferences |
app/novel/[novelId].tsx |
Webnovel details and chapters |
app/reader/[chapterId].tsx |
Chapter reading and narration |
Composition lives in src/app/: navigation/ owns navigators, providers/ owns global React providers, bootstrap/ initializes infrastructure, and config/ holds application configuration.
Each directory under src/features/ contains the interface and behavior of a specific domain:
model/contains types, transformations, and pure rules without React;hooks/contains ViewModels, state, actions, effects, and orchestration;components/contains views used only by that feature;api/contains domain-specific persistence and external adapters;*.screen.tsxis the declarative View;index.tsis the feature's public entry point.
Screens are composed of smaller components and consume hooks that act as View Models. These hooks coordinate state, navigation, and infrastructure calls, leaving components focused on rendering and user interaction.
src/shared/ contains code genuinely reused across features: the design system, global hooks, i18n contracts, domain contracts, and generic utilities. Code starts inside a feature and moves to shared only after it has more than one consumer.
src/infra/ exposes technical capabilities rather than business operations: SQLite migration, chapter file storage, platform PDF extraction, speech playback, and device brightness. Operations such as listing novels, saving reading progress, or updating settings stay in the owning feature's api/ directory.
PDF extraction uses modules with platform suffixes:
pdf.native.tscontains the implementation shared by Android and iOS;pdf.android.tsandpdf.ios.tsforward to the native implementation;pdf.web.tsadapts PDF.js loading for the browser;pdf.tsacts as a fallback for platforms without a dedicated implementation.
This pattern keeps technical differences isolated without spreading platform conditionals throughout the import interface.
The application creates the webnovel-reader.db database through SQLiteProvider. Migrations are incremental and tracked using PRAGMA user_version; foreign keys are enabled, and the database uses WAL mode.
| Table | Contents |
|---|---|
novels |
Webnovel metadata |
chapters |
Metadata, order, source, and file URI for each chapter |
reading_progress |
Current chapter, narration position, and scroll ratio for each webnovel |
reader_settings |
Font size, line height, and theme |
audio_settings |
Voice, language, playback speed, and pitch |
app_settings |
Interface language |
Normalized chapter texts are stored separately at:
<app-documents>/webnovels/<novelId>/<chapterId>.txt
Operations that create a webnovel and its chapters use an exclusive transaction, preventing a partially saved catalog if an operation fails.
webnovel-reader/
├── app/ # Thin Expo Router route adapters
├── src/
│ ├── app/ # Navigation, providers, bootstrap, and config
│ ├── features/
│ │ ├── importer/ # api, model, hooks, components, and View
│ │ ├── library/
│ │ ├── reader/
│ │ └── settings/
│ ├── infra/ # Storage, files, speech, and device capabilities
│ └── shared/
│ ├── design-system/# Global components, tokens, and theme contract
│ ├── components/ # Other global components
│ ├── hooks/
│ ├── i18n/
│ ├── types/
│ └── utils/
├── assets/images/ # Icons, splash screen, and static images
├── shims/ # Native dependency compatibility shims
├── scripts/ # Project utility scripts
├── app.json # Expo configuration
├── metro.config.js # Metro bundler configuration
├── package.json # Dependencies and commands
└── tsconfig.json # TypeScript configuration
- A recent Node.js LTS release;
- npm;
- Expo Go, an Android emulator, an iOS simulator, or a modern browser.
The iOS simulator requires macOS and Xcode. Android can be run on a physical device or an emulator configured through Android Studio.
git clone <repository-url>
cd webnovel-reader
npm installStart the Expo development server:
npm startAlternatively, open a specific platform directly:
npm run android
npm run ios
npm run webThe current application does not require environment variables.
Before submitting changes, run:
npm run lint
npx tsc --noEmitTypeScript is configured in strict mode. The project does not currently have an automated testing framework or coverage threshold, so changes should also be verified manually on the affected platforms.
- Keep routes small and delegate their implementation to
src/features/. - Keep Screens declarative and move state, actions, navigation, and effects to ViewModel hooks.
- Keep feature models free from React and native framework dependencies.
- Keep business operations in feature
api/modules and technical capabilities ininfra/. - Promote local code to
shared/only when multiple features use it. - Use PascalCase for components and camelCase for functions and hooks.
- Use the
@/alias for imports fromsrc/. - Keep platform variants next to their base module with suffixes such as
.ios.tsx,.android.ts,.native.ts, or.web.ts. - Follow the existing style: two-space indentation, single quotes, semicolons, and trailing commas in multiline structures.
- Image-based PDFs require OCR and cannot currently be imported.
- The library is entirely local and does not yet support cloud synchronization or backup.
- There is no authentication, remote catalog, or automatic chapter download.
- No automated test suite is currently configured.
- TTS voice quality and availability depend on the operating system and the voices installed on the device.
- OCR support for scanned documents.
- Editing and removal of webnovels or chapters.
- Custom covers and richer metadata.
- Search, filters, and collection organization.
- Export, backup, and synchronization across devices.
- Unit tests for helpers, the repository, and View Models.
- Integration tests for imports, reading progress, and database migrations.
The project is currently a functional MVP. Its core flows—content import, local library, offline reading, customization, progress persistence, internationalization, and narration—are implemented. Cloud features, OCR, and advanced library management remain outside the current scope.