lekterion #
A reader and language-study tool for philosophical texts in their original languages — German (Kant, Husserl), Ancient Greek (Aristotle), and Latin (Descartes). Inspired by the Perseus Hopper reader: select any span of text to gloss it, translate it, or hear it read aloud, with page-accurate citations (Akademie, Bekker, AT …) and side-by-side facsimile scans.
Features #
- Reading view with locus anchors and canonical citation schemes — every
selection carries a citation like
KrV A 51orMet. 980a21, and every position is a shareable URL. - Gloss & translate — select a word or passage and one Claude call
returns a contextual gloss, a full translation, and a word-by-word literal
alignment, in the reader's chosen target language. Results are cached
content-addressed by
hash(quote + citation), so each span is generated at most once, shared by all readers, and reopenable via?art=links. - Read aloud — OpenAI TTS synthesizes the original-language span once and caches the clip; single words are warmed from multi-word clips.
- Facsimile pane — synchronized page scans (Husserl page images in-repo; PDF rendering via pdf.js) alongside the transcription.
- Fluency tracking — per-reader word-fluency signals tint the text, doing triple duty as reading aid, study signal, and OCR-proofreading radar.
- Corrections — readers can propose text corrections stored as diffs over the immutable canonical source; admins can promote them globally.
- Agent/CLI-friendly corpus — each text is also served as canonical
Markdown (
/corpus/<id>.md, discoverable via/llms.txt), no JS required.
Stack #
Vite + React SPA (shadcn/Radix UI) · Convex backend
(state, AI-result cache, AI proxying via actions) · Cloudflare Workers static
hosting · Claude (gloss/translation) · OpenAI (TTS). The canonical texts are
Markdown files in sources/, compiled at build time by a deterministic ingest
(scripts/ingest/) into a static document model — Convex holds only mutable,
per-reader, and cache data.
Getting started #
Prereqs: bun.
bun install
bunx convex dev # provisions a dev deployment, writes .env.local
bun run dev # ingests sources/ then starts Vite
The AI features need provider keys in the Convex environment (they never
reach the client). Put LEKTERION_ANTHROPIC_API_KEY and
LEKTERION_OPENAI_API_KEY in .env.local, then:
bun run convex:env # forwards the keys to the Convex deployment
Paid AI calls (gloss/translate, new TTS synthesis) require a signed-in reader
and are per-reader rate limited (convex/limits.ts); anonymous readers get
every cached result for free. Sign-in goes through a small external JWT broker
(src/auth/, convex/auth.config.ts) — a fork will want to point those at
its own issuer.
Corpus and licensing #
- Code is MIT-licensed.
- Texts in
sources/are public-domain works: Kant (Kritik der reinen Vernunft A/B, Grundlegung, Was heißt: sich im Denken orientieren?), Husserl (Ideen I), Aristotle (Metaphysics, Physics, Rhetoric, De Interpretatione), Descartes (Meditationes, Principia). Transcription provenance is credited in each file's header; the Kant KrV A text is rebuilt from the Deutsches Textarchiv double-keyed transcription (CC BY-SA 4.0 — see scripts/sources/), and the Aristotle texts come from PerseusDL. - The ingest also supports local-only texts that are not part of the
repository (editions that may not be redistributed): anything under a
gitignored
sources/subdirectory is served in the app but gets no Markdown export, no/llms.txtentry, and is never committed.