About Unscrolling

We hated doomscrolling for 90+ minutes per day. So we built an agent that turns that time into a 5-minute podcast, so you can still catch up with everything without losing 7% of your day.

Unscrolling is that AI-powered briefing assistant: it turns your interests into personalized podcast and video briefings. Below we describe what inspired us, what we learned, how we built it, and the challenges we faced.

Launch Unscrolling


What inspired us

We were inspired by a simple frustration: information overload that leads to doomscrolling. Endless scrolling through feeds, tabs, and notifications rarely leads to understanding. We wanted to “unscroll”, meaning that we wanted to step back and get a single, coherent digest of what matters to you, in your own time.

We imagined a briefing that:

  • Aggregates from the places you already care about: YouTube, X (Twitter), LinkedIn, news, and podcasts
  • Sounds like a short podcast you can listen to on a walk or commute
  • Optionally becomes a short video with synced visuals for when you prefer to watch

So we set out to build Unscrolling: one place where your interests become a daily (or on-demand) briefing, generated and read to you by AI.


How we built it

  • Backend (Python / FastAPI)

    • Summary generation: Google Gemini (google-genai) turns lists of item contents into a single digest script (short or ~3-min variant).
    • Podcast/TTS: Gemini TTS produces 24 kHz mono WAV; long scripts are chunked, synthesized per chunk, then concatenated. We cache generated audio per run/briefing to avoid re-synthesis.
    • Video generation: A builder module splits the transcript into segments, merges them to respect a minimum slide duration, generates slide images (gradient + text with Pillow), and uses moviepy to composite audio + images into an MP4 (e.g. 1280×720, 30 fps).
    • Content ingestion:
    • YouTube: transcripts via youtube-transcript-api; optional metadata via YouTube Data API.
    • News: Google News RSS + feedparser; optional URL resolution via googlenewsdecoder.
    • X/Twitter: Nitter-based RSS where configured.
    • LinkedIn / other: Optional Apify or similar for profile feeds.
    • Extraction: For arbitrary URLs (articles, threads), we fetch HTML with httpx, send a trimmed payload to Gemini, and extract title + main body for summarization.
    • Assistant: A chat endpoint that sends conversation history plus user context (name, topics, sources, latest briefing text) to Gemini and returns the assistant reply.
    • Data: SQLAlchemy with SQLite (or Postgres); models for users, sources, topic preferences, runs, summaries, cached audio, bookmarks, and settings (e.g. briefing frequency, length, voice style).
  • Frontend (React + TypeScript + Vite)

    • UI: shadcn/ui, Tailwind CSS, Framer Motion for layout and animations.
    • State: TanStack Query for server state; React context for auth, audio playback, and chat.
    • Flows: Explore (topics/sources), Today’s briefings (cards with play/pause, progress, expand/collapse), bookmarks and favourites, settings (frequency, length, voice), global audio player, chat sidebar, and video briefing popup (premium/trial).
    • Audio: Playback of cached or streaming briefing audio with a visible progress bar and generation progress when TTS is running.
  • APIs and secrets: Configuration via pydantic-settings and .env: Gemini API key (required for summaries, TTS, chat, extraction), optional ElevenLabs, YouTube Data API key, Nitter base URL, Apify token, database URL, CORS origins.

Built With

Share this project:

Updates