Skip to content

Naman-64000/ReadShift

Repository files navigation

⚡ ReadShift — Speed Reading Trainer

Train your brain to read faster without sacrificing comprehension. Targeting GMAT · CAT · Competitive Exam Candidates v1.0 · June 2026


Table of Contents

  1. Project Overview
  2. Tech Stack
  3. Monorepo Structure
  4. Prerequisites
  5. Local Development Setup
  6. Environment Variables
  7. Database Setup
  8. Running the App
  9. Testing
  10. Background Jobs
  11. Database Schema
  12. API Reference
  13. Build Phases & Milestones
  14. Deployment
  15. CI/CD Pipeline
  16. Scientific Foundation

1. Project Overview

ReadShift is a web application that trains exam candidates to read faster without degrading comprehension. It uses three clinically-backed techniques — phrase-chunk highlighting, text fading (Reading Acceleration Effect), and a pacing guide — combined in an adaptive session engine that responds to a user's real-time WPM baseline.

Core Goals

  • Target an increase in reading speed by 20–40% over 4–6 weeks of daily practice (Projected target; pending user cohort A/B testing)
  • Maintain or improve comprehension accuracy (target: ≥ 75% MCQ accuracy at target WPM)
  • Use cognitively realistic techniques — no artificial one-word RSVP flashing
  • Serve high-quality, exam-relevant passages dynamically (no repeated content)
  • Give users clear progress feedback: WPM trend, accuracy trend, session history

2. Tech Stack

Frontend (/client)

Technology Version Purpose
React 18 Component architecture for the session state machine
TypeScript 5.4 End-to-end type safety
Vite 5 Build tooling and dev server
Tailwind CSS 3.4 Utility-first styling
Framer Motion 11 Chunk highlight transitions and animations
Zustand 4.5 Lightweight state management (session + user state)
React Router v6 Client-side routing
Recharts 2.12 WPM and accuracy trend charts on dashboard
Axios 1.7 HTTP client with interceptors for auth
Supabase Auth JS 2.x Authentication UI/session management via Supabase Auth
vite-plugin-pwa 1.3 PWA manifest + service worker for offline caching

Backend (/server)

Technology Version Purpose
Node.js 20 LTS Runtime
TypeScript 5.4 Type-safe server code
Express 4.19 HTTP framework
Prisma 5.14 Type-safe ORM, schema-as-code, migrations
PostgreSQL 15 Primary relational database
Redis 7 BullMQ job queue backing store & dashboard caching
BullMQ 5.7 Background job queue (passage generation, pool health)
ioredis 5.3 Redis client (BullMQ-compatible)
Pino 9 Structured JSON logging
Zod 3.23 Runtime request body validation
jose 5 JWT verification (Supabase JWKS)
@google/generative-ai 0.24 Google Gemini API for passage + MCQ generation
swagger-jsdoc 6 Generates OpenAPI 3.0 spec from JSDoc annotations
swagger-ui-express 5 Serves interactive Swagger UI at /api-docs

Infrastructure

Technology Purpose
Docker + Docker Compose Containerises all four services (postgres, redis, backend, frontend)
nginx Serves the production React build with SPA fallback routing
GitHub Actions CI pipeline: type-check → test → Docker build on every push to main

Testing

Technology Purpose
Vitest Unit + integration test runner (server & client)
supertest HTTP integration testing for Express routes
@testing-library/react React component testing utilities
Playwright E2E regression tests (timer drift spec)

⚡ Latency & Caching Performance

To minimize database load and ensure instantaneous UI response, ReadShift implements caching on the complex, computationally-heavy dashboard metrics calculation:

  • Target Endpoint: GET /api/dashboard/summary
  • Caching Strategy: Redis Key-Value store with a 15-minute Time-to-Live (TTL), auto-invalidated on session submission or calibration update.

ReadShift includes a verifiable performance benchmark script to compare database and cache access latency. You can run the benchmark in two modes to see the difference between a local development container and a simulated production environment.

📊 Performance Comparison Tables

1. Local Docker Mode (Default)

Useful for local integration checking and verifying caching correctness with a warm local PostgreSQL instance (no network latency and small dataset of 50 rows).

  • Command: npm run benchmark:perf
  • Results:
    Metric Direct PostgreSQL (Cache Miss) Redis Caching (Cache Hit) Latency Reduction Speed Factor
    Cold Start Response ~307.9 ms ~0.17 ms 99.9% ~1790x faster
    Warm Query Response ~0.33 ms ~0.17 ms 47.4% ~1.9x faster
2. Simulated Production Mode

Simulates a real cloud deployment (e.g., Railway/Render with a PostgreSQL RTT network delay of 120ms and a realistic dataset of 1,000+ session records).

  • Command: npm run benchmark:perf -- --simulate-production
  • Results:
    Metric Direct PostgreSQL (Cache Miss) Redis Caching (Cache Hit) Latency Reduction Speed Factor
    Cold Start Response ~410.4 ms ~5.6 ms 98.6% ~73x faster
    Warm Query Response ~267.6 ms ~5.6 ms 97.9% ~48x faster

3. Monorepo Structure

ReadShift/                          # Monorepo root
├── package.json                    # Workspace root (npm workspaces)
├── docker-compose.yml              # All four services: postgres, redis, backend, frontend
├── .env.example                    # All required env vars (copy → .env)
├── .gitignore
├── PRODUCTION_GUIDE.md             # Step-by-step deployment guide (Render, Vercel, Docker)
│
├── .github/
│   └── workflows/
│       └── ci.yml                  # GitHub Actions: type-check → test → Docker build
│
├── prisma/
│   ├── schema.prisma               # Complete DB schema (10 tables)
│   └── seed.ts                     # Dev/staging seed data
│
├── e2e/                            # Playwright end-to-end tests
│   ├── playwright.config.ts
│   └── specs/
│       └── timer-drift.spec.ts     # Timer accuracy regression tests
│
├── artifacts/
│   └── lighthouse-reading.json     # Lighthouse audit output
│
├── client/                         # React 18 + Vite frontend
│   ├── package.json
│   ├── Dockerfile                  # Multi-stage build → nginx production image
│   ├── nginx.conf                  # SPA fallback routing + cache headers
│   ├── vite.config.ts              # Vite + PWA plugin + production build config
│   ├── vitest.config.ts            # Vitest config (jsdom environment)
│   ├── tailwind.config.js
│   ├── tsconfig.json
│   ├── index.html
│   ├── public/
│   │   ├── pwa-192x192.png         # PWA icon (192×192)
│   │   └── pwa-512x512.png         # PWA icon (512×512)
│   └── src/
│       ├── main.tsx                # Entry point — mounts React + Supabase + Router
│       ├── App.tsx                 # Route tree
│       ├── index.css               # Tailwind base + design tokens
│       │
│       ├── __tests__/              # Vitest unit tests
│       │   ├── setup.ts            # @testing-library/jest-dom setup
│       │   └── sessionStore.test.ts # Zustand session state machine tests
│       │
│       ├── screens/                # One file per screen/route
│       │   ├── AuthScreen.tsx
│       │   ├── OnboardingScreen.tsx
│       │   ├── CalibrationScreen.tsx
│       │   ├── SessionConfigScreen.tsx
│       │   ├── ReadingScreen.tsx
│       │   ├── MCQScreen.tsx
│       │   ├── ResultsScreen.tsx
│       │   ├── DashboardScreen.tsx
│       │   ├── SettingsScreen.tsx
│       │   ├── AdminScreen.tsx          # Admin-only panel (passage/user management)
│       │   └── MetronomeDrillScreen.tsx # Subvocalization metronome drills
│       │
│       ├── components/
│       │   ├── session/            # Reading engine, WPM slider, MCQ card, result card, progress bar
│       │   ├── dashboard/          # WPM chart, accuracy chart, stat card, streak badge, recommendation card, advanced diagnostics
│       │   ├── onboarding/         # Domain selector, reading aid toggle, step indicator
│       │   └── shared/             # Button, Navbar, LoadingSpinner, ErrorBoundary, Toast
│       │
│       ├── store/                  # Zustand state slices
│       │   ├── index.ts            # Barrel export
│       │   ├── userSlice.ts        # User + preferences state
│       │   ├── sessionSlice.ts     # Active session state machine
│       │   ├── dashboardSlice.ts   # Dashboard summary cache
│       │   └── uiSlice.ts          # Toasts, modals, fullscreen, theme
│       │
│       ├── hooks/                  # Custom React hooks
│       │   ├── useReadingTimer.ts  # Drift-corrected interval timer
│       │   ├── useSession.ts       # Session store wrapper + computed values
│       │   ├── useDashboard.ts     # Dashboard data fetcher
│       │   └── useUserProfile.ts   # User profile loader
│       │
│       ├── lib/
│       │   ├── apiClient.ts        # Axios instance + Supabase JWT interceptor
│       │   ├── supabase.ts         # Supabase client initialization
│       │   ├── utils.ts            # WPM math, formatting helpers
│       │   └── constants.ts        # WPM levels, domains, allowed values
│       │
│       └── types/                  # TypeScript interfaces
│           └── index.ts            # Barrel exports
│
└── server/                         # Node.js + Express backend
    ├── package.json
    ├── tsconfig.json
    ├── Dockerfile                  # Multi-stage build → production Node image
    ├── vitest.config.ts            # Vitest config (node environment)
    └── src/
        ├── index.ts                # Express app entry + worker registration
        ├── worker.ts               # BullMQ worker startup
        ├── swagger.ts              # OpenAPI 3.0 spec (swagger-jsdoc)
        │
        ├── routes/                 # Router modules (thin — delegate to controllers)
        │   ├── health.ts           # GET /healthz (DB + Redis liveness check)
        │   ├── users.ts            # GET /me, POST /, PATCH /me/preferences, DELETE /me
        │   ├── sessions.ts         # POST /start, POST /, GET /, GET /:id, GET /domain-status
        │   ├── passages.ts         # GET /, POST /:id/flag
        │   ├── calibrations.ts     # POST /, GET /, GET /latest
        │   ├── dashboard.ts        # GET /summary
        │   ├── admin.ts            # Admin-only passage/user management
        │   └── drills.ts           # POST /start, POST /complete (metronome drills)
        │
        ├── controllers/            # Request handlers (validate → call service → respond)
        │   ├── users.ts
        │   ├── sessions.ts
        │   ├── passages.ts
        │   ├── calibrations.ts
        │   ├── dashboard.ts
        │   ├── admin.ts
        │   └── drills.ts
        │
        ├── services/               # Business logic (no Express types)
        │   ├── sessionService.ts   # pickPassage(), createSession(), adaptive difficulty
        │   ├── passageService.ts   # getPoolDepth(), getUnseen(), flagPassage()
        │   ├── dashboardService.ts # buildSummary() with Redis caching
        │   ├── aiService.ts        # generatePassage(), generateQuestions()
        │   ├── authService.ts      # verifyToken(), getUserBySupabaseId()
        │   └── passageQualityService.ts  # Passage quality scoring + filtering
        │
        ├── middleware/
        │   ├── auth.ts             # requireAuth — validates Supabase JWT
        │   ├── admin.ts            # requireAdmin — is_admin flag guard
        │   ├── timezone.ts         # Reads X-Timezone-Offset header for streak logic
        │   ├── rateLimiter.ts      # globalRateLimit (200 req/min), sessionRateLimit (20/hr)
        │   └── errorHandler.ts     # Global error → JSON envelope mapper
        │
        ├── jobs/                   # BullMQ workers
        │   ├── passageWarmingJob.ts # Generates passages via Gemini when pool is low
        │   ├── poolHealthJob.ts     # Scheduled: checks pool depth, enqueues warming jobs
        │   └── streakResetJob.ts    # Daily: timezone-aware streak reset for inactive users
        │
        ├── __tests__/              # Vitest integration tests
        │   └── health.test.ts      # /healthz + /health endpoint tests (supertest)
        │
        ├── scripts/
        │   └── benchmarkDashboard.ts  # Performance benchmark: DB vs Redis cache latency
        │
        └── lib/
            ├── prisma.ts           # PrismaClient singleton
            ├── redis.ts            # ioredis singleton (BullMQ-compatible)
            ├── queue.ts            # BullMQ Queue instances + queue name constants
            ├── env.ts              # dotenv loader
            └── logger.ts           # Pino logger (pretty in dev, JSON in prod)

4. Prerequisites

Requirement Version Install
Node.js 20 LTS nodejs.org or nvm install 20
npm 10+ Bundled with Node.js 20
Docker Desktop Latest docker.com
Git 2.x+ Pre-installed on macOS

You will also need accounts and API keys for:


5. Local Development Setup

Step 1 — Clone and install dependencies

git clone <repo-url> ReadShift
cd ReadShift
npm install

Step 2 — Configure environment variables

cp .env.example .env

Step 3 — Start the database and Redis

# Starts only postgres + redis (for local dev with npm run dev)
docker compose up postgres redis -d

Step 4 — Run database migrations and seed

cd server
npm run db:generate
npm run db:migrate
npm run db:seed

Step 5 — Start the development servers

npm run dev

6. Environment Variables

Variable Required Description
NODE_ENV development | staging | production
DATABASE_URL Full Prisma PostgreSQL connection string
REDIS_URL Redis connection URL
PORT Express server port (default 3001)
CORS_ORIGIN Allowed CORS origin for the API (Vite dev: http://localhost:5173)
SUPABASE_URL Supabase project URL
SUPABASE_SERVICE_ROLE_KEY Supabase service role key (server-side JWT verification)
VITE_SUPABASE_URL Same as above — exposed to the Vite client
VITE_SUPABASE_ANON_KEY Supabase anon key — exposed to the Vite client
GEMINI_API_KEY Google Gemini API key
VITE_API_BASE_URL Backend API base URL seen by the client
LOG_LEVEL debug | info | warn | error
PASSAGE_POOL_MIN_THRESHOLD Passages per domain before top-up triggers (default 50)
VITE_DEV_MODE Set to "true" in dev to bypass Supabase email confirmation check

7. Database Setup

Schema overview

The Prisma schema is at prisma/schema.prisma and defines 10 tables:

Table Purpose
users Core identity record, stores Supabase UID
user_prefs Reading preferences — one row per user
passages Shared AI-generated content pool (250–350 words each)
questions 3 MCQs per passage (main_idea, inference, vocab)
sessions One row per completed reading session
responses One MCQ answer row per question per session
calibrations Baseline WPM measurements per user
user_passage_seen Join table preventing passage repetition per user
passage_assignments Tracks which passage was assigned per user + session context
drill_passages Short passages (65–85 words) for metronome subvocalization drills
user_drill_seen Join table preventing drill passage repetition per user

Common database commands

# From /server

npm run db:generate    # Regenerate Prisma client after schema changes
npm run db:migrate     # Apply pending migrations (creates new migration file)
npm run db:seed        # Run prisma/seed.ts to populate dev data
npm run db:studio      # Open Prisma Studio at http://localhost:5555

8. Running the App

Development (both services)

# From monorepo root
npm run dev

Development (individual services)

# Frontend only
cd client && npm run dev

# Backend only
cd server && npm run dev

Type checking

npm run type-check

Linting

npm run lint

Quality Assurance (QA) & E2E Testing

# Run Lighthouse performance audit on the reading screen
npm run qa:lighthouse:reading

# Run Playwright end-to-end tests
npm run qa:e2e:staging
npm run qa:e2e:staging:headed

Performance Benchmark

# Compare PostgreSQL vs Redis cache latency (local Docker mode)
npm run benchmark:perf

# Simulated production mode (120ms DB RTT, 1000+ rows)
npm run benchmark:perf -- --simulate-production

9. Testing

Server — Vitest + Supertest

cd server
npm test              # run all tests once
npm run test:watch    # watch mode during development

Client — Vitest + Testing Library

cd client
npm test              # run all tests once
npm run test:watch    # watch mode during development

What is covered

Test file Scope What it verifies
server/src/__tests__/health.test.ts Integration GET /healthz returns 200 + all checks ok; /health alias works
client/src/__tests__/sessionStore.test.ts Unit Zustand state machine: idle→reading→mcq transitions, error path, answer deduplication, reset

10. Background Jobs

Job Queue Schedule Purpose
passageWarmingJob passage-warming On-demand Calls Gemini to generate passages + MCQs
poolHealthJob pool-health Every 30 min Checks passage pool depth, enqueues warming jobs
streakResetJob streak-reset Daily Timezone-aware streak reset for inactive users

11. Database Schema

Content Domains

philosophy · psychology · history · arts_and_museum · society · culture · biology · science_and_technology

Pool target: 400 passages (50 per domain) before repetition.

Passage Status Lifecycle

draftreadyflaggedretired


12. API Reference

All API routes are prefixed with /api. All protected routes require a Supabase JWT in the Authorization: Bearer <token> header.

Users

Method Path Auth Description
GET /api/users/me Get authenticated user + preferences
POST /api/users Create user record on first Supabase login
PATCH /api/users/me/preferences Update reading preferences (partial)
DELETE /api/users/me Delete account and all associated data

Sessions

Method Path Auth Description
POST /api/sessions/start Pick an unseen passage; returns { passage, questions }
POST /api/sessions Submit a completed session with MCQ responses
GET /api/sessions List session history (paginated)
GET /api/sessions/:id Get a single session by ID
GET /api/sessions/domain-status Unseen passage counts per domain for the current user

Passages

Method Path Auth Description
GET /api/passages List passages with pool depth summary (admin)
POST /api/passages/:id/flag Flag a passage for quality review

Calibrations

Method Path Auth Description
POST /api/calibrations Submit a calibration result
GET /api/calibrations List all calibrations for the user
GET /api/calibrations/latest Get the most recent (current baseline)

Dashboard

Method Path Auth Description
GET /api/dashboard/summary Full dashboard summary (WPM trend, accuracy, streak, recommendation) — Redis-cached

Admin (requires is_admin = true)

Method Path Auth Description
GET /api/admin/summary ✅ Admin Platform-wide stats
GET /api/admin/passages ✅ Admin List all passages with status
PATCH /api/admin/passages/:id ✅ Admin Update passage status/quality
GET /api/admin/users ✅ Admin List all users
PATCH /api/admin/users/:id ✅ Admin Update user (e.g. grant admin)
GET /api/admin/users/:id/seen-passages ✅ Admin List passages seen by a specific user
DELETE /api/admin/users/:id/seen-passages/:passageId ✅ Admin Reset seen status for a passage

Drills (Metronome Subvocalization Drills)

Method Path Auth Description
POST /api/drills/start Pick an unseen drill passage for the metronome drill
POST /api/drills/complete Submit drill result and mark passage seen

Health & Docs Endpoints

Method Path Auth Description
GET /healthz Full liveness check — returns DB + Redis status; used by Docker healthcheck
GET /health Legacy simple check — { status: "ok" }
GET /api-docs Interactive Swagger UI (OpenAPI 3.0)

API Response Envelope

All responses follow a consistent shape:

// Success
{ "success": true, "data": { ... } }

// Error
{ "success": false, "error": { "code": "POOL_EXHAUSTED", "message": "No passages available for this domain." } }

Known Error Codes

Code HTTP Meaning
POOL_EXHAUSTED 404 No unseen passages for the selected domain
UNAUTHORIZED 401 Missing or invalid JWT
FORBIDDEN 403 Authenticated but not permitted (e.g. non-admin on admin route)
NOT_FOUND 404 Resource does not exist
VALIDATION_ERROR 400 Request body failed Zod validation
INTERNAL_ERROR 500 Unexpected server error

13. Build Phases & Milestones

Phase 1 — Core Reading Engine (Weeks 1–2)

Goal: A user can read a hardcoded passage with chunk highlighting and see their WPM at the end.

  • Implement useReadingTimer with drift-corrected interval
  • Build ReadingEngine component (chunking, highlighting, fading, guide)
  • Build WpmSlider and SessionConfigScreen
  • Build basic ResultsScreen
  • Verify: timer accurate within 200ms over a full session (Playwright harness confirmed; timer-drift.spec.ts passes)

Phase 2 — Backend + Auth + DB (Weeks 3–4)

Goal: Users can create accounts, sessions are saved, passages are fetched from the database.

  • Configure auth + requireAuth middleware (Supabase JWT verification)
  • Implement authService.verifyToken() and user lookup/create service
  • Implement all route controllers (users, sessions, calibrations)
  • Implement sessionService.pickPassage() and createSession()
  • Seed DB with manual passages for testing (prisma/seed.ts)
  • Build CalibrationScreen and calibrationsController
  • Build AuthScreen (Supabase-powered sign-in/sign-up UI)

Phase 3 — AI Content Pipeline + Dashboard (Weeks 5–6)

Goal: Gemini generates passages and MCQs. Dashboard shows real data.

  • Implement aiService.generatePassage() and generateQuestions() (Gemini-based)
  • Implement passageWarmingJob BullMQ worker
  • Implement poolHealthJob scheduler
  • Implement dashboardService.buildSummary() with Redis caching
  • Build DashboardScreen with WpmChart, AccuracyChart, AdvancedDiagnostics
  • Build MCQScreen with per-question timer (configurable, default off)
  • Implement passageQualityService for AI output validation and scoring

Phase 4 — Polish + Launch (Weeks 7–8)

Goal: App feels complete: smooth UX, adaptive difficulty, onboarding, error handling.

  • Implement adaptive difficulty (level promotion and demotion logic)
  • Implement Spaced Repetition for resurfacing challenging passages
  • Implement Timezone-Aware streak tracking
  • Periodic Recalibration triggers
  • Build OnboardingScreen multi-step flow
  • Implement SettingsScreen with auto-save preferences
  • Build AdminScreen (passage + user management for is_admin users)
  • Build MetronomeDrillScreen (subvocalization suppression drills)
  • Add PWA support via vite-plugin-pwa (service worker + manifest + icons)
  • Lighthouse score ≥ 85 on ReadingScreen (Achieved via PWA caching)
  • All E2E tests pass in staging (Timer drift Playwright specs passed)
  • [~] Polish all animations (Framer Motion) — ongoing
  • [~] Ensure mobile responsiveness (375px viewport) — ReadingScreen pass completed; full-app pass pending

Phase 5 — Production Hardening

Goal: Containerised, CI-tested, fully documented, ready for public deployment.

  • Dockerfiles for backend (multi-stage Node) and frontend (Vite → nginx)
  • docker-compose.yml updated with all four services + health checks
  • GitHub Actions CI pipeline (type-check, Vitest tests, Docker build)
  • /healthz endpoint — checks DB + Redis liveness for orchestrator probes
  • OpenAPI 3.0 spec (swagger-jsdoc) + Swagger UI at /api-docs
  • Vitest unit tests — Zustand session state machine (client)
  • Vitest integration tests — health endpoints via supertest (server)
  • Production Vite build config — content-hashed assets, manual vendor chunks
  • PWA icons (192×192, 512×512) added to client/public/
  • PRODUCTION_GUIDE.md — full Docker, CI/CD, env-var, health-check documentation

Milestones

Milestone Week Done When
M1: Reading Engine 2 Chunk highlighting + timer accurate across 4 browsers
M2: Auth + DB 4 Registration, session save, no passage repeats
M3: AI Content 6 Gemini generates, MCQs work, scores saved
M4: Full Dashboard 6 WPM trend + accuracy charts show real data < 300ms
M5: Adaptive Difficulty 7 Level promotion fires correctly on seeded test data
M6: Drills + Admin 8 Metronome drill flow complete; admin panel live
M7: Production Launch 8 All Phase 4 criteria passed, custom domain live
M8: Production Hardening 8+ Docker + CI/CD + Swagger + tests + PWA icons complete

14. Deployment

See PRODUCTION_GUIDE.md for the complete step-by-step guide. A quick summary is below.

Option A — Hosted (Recommended for free tier)

Layer Service Command / Config
Frontend Vercel Root dir: client, build: npm run build, output: dist
Backend Render Root dir: server, build: npm install && npm run build, start: node dist/index.js
Database Supabase (hosted Postgres) Copy connection string → DATABASE_URL
Redis Upstash Copy rediss:// URL → REDIS_URL

Option B — Self-hosted with Docker

# Build and start all four containers
docker compose up --build -d

# Apply DB migrations inside the backend container
docker compose exec backend npx prisma migrate deploy --schema ../prisma/schema.prisma

# Verify
curl http://localhost:3001/healthz   # {"status":"ok",...}
curl http://localhost:80             # React app HTML

Database migrations in production

# Hosted (run locally against production DB)
DATABASE_URL="postgresql://..." npx prisma migrate deploy --schema ./prisma/schema.prisma

# Docker (run inside container)
docker compose exec backend npx prisma migrate deploy --schema ../prisma/schema.prisma

15. CI/CD Pipeline

The .github/workflows/ci.yml workflow runs on every push to main or develop and on PRs to main.

Job Triggers What it does
lint-and-typecheck All pushes tsc --noEmit on server + client
test-server All pushes Runs Vitest in server/ with a Redis service container
test-client All pushes Runs Vitest in client/ (jsdom)
docker-build After all tests pass Builds backend + frontend Docker images

To enable Docker image push to a registry, add DOCKER_USERNAME and DOCKER_PASSWORD to GitHub repo secrets and set push: true in the workflow.


16. Scientific Foundation

Technique 1 — Phrase Chunk Highlighting

Fluent readers make 3–4 fixations per line, each covering a 3–5 word cluster. The app advances a highlight box in phrase-sized chunks (2–3 words, configurable) at the user's target WPM. The full text remains visible — unlike RSVP, peripheral vision is engaged and re-reading is possible.

Technique 2 — Text Fading (Reading Acceleration Effect)

A 2024 Frontiers in Psychology study (N=90) found participants read 40% faster under the Reading Acceleration Procedure while maintaining the same comprehension. In fading mode, text behind the highlight fades to 20% opacity after a short delay, training forward momentum without fully removing the text. Off by default.

Technique 3 — Pacing Guide (Meta-Guiding)

A 1px horizontal guide line moves down the passage at the line-crossing rate. Suppresses regressions (the habit of re-reading) and gives the eye a target to follow. Enabled by default.

Technique 4 — Metronome Subvocalization Drill

Short 65–85 word passages read under a rhythmic audio metronome cue. Gradually increases BPM across 6 levels to reduce inner-speech pacing. Comprehension verified with a 2-option question after each drill.

What the App Does NOT Use

Technique Why Excluded
Pure RSVP (1-word flash) Eliminates natural eye movement; comprehension drops sharply on dense argumentative text
Bionic Reading 2025 eye-tracking study found no significant difference in fixation duration, count, or speed vs standard text
Subvocalization elimination Fully eliminating inner speech reduces comprehension on complex text — the app reduces, not eliminates

This repository is the authoritative reference for the ReadShift v1 build. Questions about any section should be directed to the product lead. Updates require a version bump.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages