About LibTrails

Trail-finding across your book library using semantic search and topic clustering.

What is this?

LibTrails helps you discover conceptual connections across a book collection. It parses EPUBs into text chunks, uses LLMs to extract granular topics from each chunk, generates semantic embeddings, and builds a multi-tier topic hierarchy — all stored locally in SQLite.

  • Find books that discuss similar themes across genres and centuries
  • Discover unexpected connections between books via shared topics
  • Explore a 3D galaxy where each sphere is a topic community, colored by theme
  • Search across every layer — books, text chunks, topics, and themes — simultaneously

The Library

This demo runs on a curated collection of 100 Project Gutenberg classics spanning nearly 3,000 years of written thought — from Homer's Iliad (~800 BC) and Sun Tzu's The Art of War (~500 BC) through to F. Scott Fitzgerald's The Great Gatsby (1925).

The selection was designed to maximize thematic bridge density — books that connect across categories to produce rich, interconnected topic clusters. Every title is a recognizable classic, chosen for how it links to others in the collection rather than just its individual significance.

100
Books
31,849
Text chunks
~3,000 yrs
~800 BC – 1925 AD
Victorian British Fiction — Austen, Dickens, the Brontes, Hardy, Eliot, Wilde
American Classics — Melville, Twain, Hawthorne, Fitzgerald, Wharton, Thoreau
Russian Literature — Dostoevsky, Tolstoy, Turgenev, Gogol, Lermontov
Early Sci-Fi & Gothic — Shelley, Stoker, Wells, Verne, Poe, Stevenson
Philosophy & Essays — Plato, Aristotle, Machiavelli, Nietzsche, Mill, Emerson
World Classics — Homer, Dante, Cervantes, Hugo, Dumas, Flaubert
Drama — Shakespeare, Ibsen, Wilde, Chekhov
Nonfiction & Political Thought — Darwin, Paine, Marx, Wollstonecraft, Du Bois

Author diversity is capped at four titles per author, each chosen for thematic distinctness. The result is a library where Dostoevsky's guilt and redemption connect to Hugo and Shakespeare's tragedies, Darwin's naturalism links to London and Thoreau's wilderness writing, and Ibsen's gender critique echoes across the Brontes, Chopin, and Wollstonecraft.

The Pipeline

121,118
Extracted topics
2,468
Leiden clusters
202
Topic communities
26
Themes
6
Search signals

Stage 1: Topic Extraction

Parse & Chunk

EPUBs are parsed with selectolax (HTML block tags converted to paragraph breaks) and recursively split into ~500-word chunks — first at paragraph boundaries, then sentences, then words as a last resort. The 100-book demo library produces 31,849 chunks.

Two-Pass LLM Extraction

Pass 1: A larger model (gemma3:27b) reads the first few chunks plus Calibre metadata (tags, description, series) to extract 5–10 book-level themes in a single call.

Pass 2: A smaller model (gemma3:4b or 12b) extracts chunk-level topics, contextualized with the book themes from Pass 1. This produces domain-specific noun phrases instead of generic single words — yielding 121,118 deduplicated topics across the demo library.

Stage 2: Graph & Clustering

Embed & Deduplicate

All topics get 384-dimensional embeddings via BGE-small-en-v1.5. A two-tier deduplication then merges near-duplicates: cosine similarity >0.95 merges unconditionally, while 0.85–0.95 only merges if both topics share at least one book — preventing cross-domain conflation (e.g., "energy manipulation" in fantasy vs. psychology).

Co-occurrence & KNN Graph

Topic pairs that appear in the same chunk get Pointwise Mutual Information (PMI) scores. A KNN graph is built from two edge types: co-occurrence edges weighted by PMI with a book-count boost (PMI × (1 + log(1 + book_count))), and embedding-similarity edges from each topic's 10 nearest neighbors (cosine ≥ 0.65). Only genuinely surprising co-occurrences make the cut (PMI ≥ 1.0).

First Leiden Pass: Topic Clusters

High-degree "hub" topics (95th percentile) are removed before clustering — these generic terms would create artificially large, incoherent groups. The Leiden algorithm then runs with the CPM (Constant Potts Model) partition type at resolution 0.001, producing 2,468 fine-grained topic clusters. Each cluster groups topics that are tightly related — for example, "categorical imperative," "moral duty," and "Kantian ethics" all land in one cluster. The cluster's label is drawn from its most representative topic, so you see names like "Kantian Ethics & Moral Philosophy" rather than raw topic strings.

These are the labeled chips you see throughout the app — on topic detail pages, in universe popups, and in search results. When a topic page shows "27 clusters," that means 27 distinct sub-themes make up that broader topic community. Clusters also power the search engine: topic and chunk vectors are indexed in sqlite-vec for cosine similarity lookups, and FTS5 indexes cluster labels, topic labels, and chunk text for keyword matching.

Second Leiden Pass: Topic Communities

A second Leiden pass runs on the same topic graph with a different resolution, grouping clusters into 202 broader communities. These are the browsable entries on the Topics page and the spheres in the Universe view. Each community is a coherent theme like "Victorian Social Norms," "Nautical Adventure," or "Ancient Greek Philosophy" — large enough to span multiple books, small enough to be meaningful.

Themes via K-Means

K-means groups the cluster centroids into 26 high-level themes based on embedding similarity. These appear on the Themes page with names like "Adventure & Human Folly," "Literary Classics & Philosophy," or "Nature & Rural Life" — LLM-generated and human-refined.

Stage 3: Visualization

3D Projection & Semantic Colors

Community centroids are projected into 3D with UMAP (cosine metric, n_neighbors=15). Theme embeddings are mapped onto a single PCA axis, then each theme's position becomes a hue value — so semantically similar themes share similar colors in the Universe. The result is rendered with React Three Fiber using instanced meshes for performance.

Reading the UI

The pipeline produces a three-tier hierarchy. Here's how each level maps to what you see:

Clusters

The labeled chips on topic pages and universe popups. Each chip names a tight group of related topics (e.g., "Kantian Ethics & Moral Philosophy"). When a topic card shows "27 clusters," those are its 27 distinct sub-themes. Clusters are the finest granularity exposed in the UI.

Topics

The cards on the Topics page and the spheres in the Universe. Each topic is a community of clusters spanning multiple books — broad enough to be interesting ("Victorian Social Norms," "Ancient Greek Philosophy") but specific enough to be coherent.

Themes

The color-coded groupings on the Themes page and the universe legend. Each theme aggregates many topics into a high-level category like "Adventure & Human Folly" or "Nature & Rural Life." Themes determine sphere colors in the universe — similar themes get similar hues.

Hybrid Search

Every page has a search bar that combines multiple retrieval signals into a single ranked result set. Rather than choosing between keyword search or semantic search, LibTrails runs both in parallel and fuses them with Reciprocal Rank Fusion (RRF).

Hybrid Book Search

When you search on the Books page, your query is evaluated against six independent retrieval signals, each producing its own ranked list:

  • 1. FTS5 book metadata — keyword search over title, author, and description
  • 2. FTS5 topic labels — keyword search across 121K topic labels, mapped back to books
  • 3. FTS5 chunk text — keyword search across 31,849 chunk passages, mapped back to books
  • 4. Semantic book theme vectors — cosine similarity against book-level theme embeddings
  • 5. Semantic book vectors — cosine similarity against whole-book embeddings (title + themes)
  • 6. Semantic chunk vectors — cosine similarity against chunk embeddings, best per book

Each result shows a colored badge indicating which signal contributed most: keyword, topic, content, theme, book, or chunk.

Reciprocal Rank Fusion

Each signal produces its own ranked list. RRF combines them by scoring each result as 1/(k+rank) across all lists, where k=60. This means a book that ranks #1 in keyword search and #5 in semantic search scores higher than one that ranks #2 in both — rewarding results that excel in at least one signal without requiring score normalization across different retrieval methods.

Scope-Aware Search

Search adapts to each page. On Books, all 6 signals rank books directly. On Topics, 4 signals surface the most relevant topic communities — topic FTS, cluster label matching, chunk FTS, and chunk semantic. On Themes, topic scores roll up to highlight matching themes, with a boost for direct label matches.

Universe Search

The Universe search bar runs the same cluster search, then aggregates results by community. Matching communities glow amber in the 3D view — the brighter the glow, the stronger the match — with a ranked sidebar list showing the top hits. This lets you visually see where a concept lives in the semantic landscape and which neighboring communities are related.

Exploring the Universe

The Universe is a 3D galaxy of 202 topic communities projected by semantic similarity — communities that share conceptual DNA are close together; unrelated ones are far apart.

Navigation

Drag to rotate, scroll to zoom, and right-drag to pan. Each sphere is a topic community — larger spheres span more books. Colors encode themes: semantically similar themes share similar hues, so you can see natural neighborhoods form in 3D space.

Interacting

Hover over a sphere to see its label and the books it spans. Click to open a detail panel with the community's cluster labels and all contributing books. Use the search bar to light up matching communities — try searching for a concept like "justice" or "natural selection" to see which corners of the library discuss it.

What to Look For

Tight clusters of similarly-colored spheres reveal thematic neighborhoods — philosophy spheres near political theory, gothic fiction near psychological horror. But the interesting discoveries are the unexpected bridges: a nature-writing community sitting near a philosophy community because Thoreau and Emerson link them both.

Features

Two-Pass Extraction
Book themes from a 27b model contextualize chunk-level topic extraction by a 12b model
Multi-Provider LLM
Ollama, Gemini API, or LM Studio — swap with a CLI flag
3D Universe
Interactive Three.js galaxy with 202 topic communities, colored by semantic theme similarity
Hybrid Search
FTS5 keyword + semantic vector search across books, themes, and chunks, fused via Reciprocal Rank Fusion
Smart Deduplication
Two-tier merging: cosine >0.95 merges always, 0.85–0.95 only if same book — prevents cross-domain conflation
Three-Tier Hierarchy
Leiden clusters (2,468, with hub removal) → topic communities (202) → themes (26)

Tech Stack

Topic extraction gemma3 via Ollama / Gemini / LM Studio
Embeddings BGE-small-en-v1.5 (384 dims) via ONNX Runtime
Search Hybrid: FTS5 (BM25) + sqlite-vec (cosine) + RRF fusion
Clustering Leiden (python-igraph + leidenalg), two-pass
3D projection UMAP + PCA semantic colors
Backend FastAPI + SQLite
Frontend Astro + React Three Fiber

Inspiration

Inspired by Pieter Maes' "Reading Across Books" project and the Trails visualization.

Links