A technical report on how Schrollar is built, run and grown, as of 7 November 2026, app build 17.
note What Schrollar is. Lessons come in boxes: short, layered explanations (Hook → Why → How → Code → Try) of one idea, from Dijkstra's algorithm to how a tokenizer works to why a minor chord sounds sad. You scroll a feed of boxes, go as deep as you like, keep the ones worth remembering, and the app brings them back for review right before you would forget them.
flowchart LR
subgraph Devices
W[Website / PWA]
N[iOS and Android apps]
end
subgraph Edge["Cloudflare edge"]
CW[Worker: app, content,<br/>link previews, API proxy]
R2C[(R2: signed content)]
end
subgraph Fly["Fly.io"]
API[API ×2<br/>accounts · sync · sharing]
JOBS[Worker process<br/>jobs]
end
PG[(Postgres<br/>system of record)]
LAKE[(R2: Parquet lake)]
W & N -->|HTTPS| CW
CW --> R2C
CW -->|/api| API
API --> PG
JOBS --> PG
JOBS -->|nightly export| LAKE
CLI[Content build<br/>validate · compile · sign] -->|publish| CW
Schrollar is an offline-first client (one React codebase shipped as a website and as iOS and Android apps) that keeps everything a learner does in an on-device database and syncs it in the background through an outbox. Lessons are signed, versioned data published to object storage and served from the edge, so new content never needs an app release. A Cloudflare Worker fronts everything; the API is a TypeScript service on Fly.io backed by Postgres; background jobs compute learner models, send reminders, enforce retention and export pseudonymous analytics to a Parquet lake. Every decision the app makes for a learner is logged with its alternatives, so rules can later be replaced by learned policies and measured.
${sch.contents()}
Prefer to browse by section? Architecture · Features · Operations · Scaling Plan · Roadmap · Decisions · Glossary
| Content | 162 boxes and 21 daily puzzles across 8 worlds and 40 topics |
| Interactives | 50+ hands-on playables, from Fenwick trees to FFTs to tokenizers |
| First download (web) | 133 KB of JavaScript, gzipped; everything else loads on demand |
| Content delivery | about 55 ms to first byte from the edge cache |
| API | 2 app machines with rolling deploys, plus a separate jobs machine |
| Platforms | Web (installable PWA), iOS, Android, from one codebase |
| Releases | API, website and content deploy from CI on every merge; content ships without app releases |
This report is itself a small SilverBullet application: diagrams are Mermaid blocks rendered by a code widget, and the contents tables and page-to-page navigation are Space Lua queries over each page's frontmatter. See Library/Schrollar/Publishing.