dk.
All work

KnowledgeCity · EdTech LMS · April 2026

An entire course library. Unlocked in 60 seconds.

An AI pipeline that segments existing course transcripts into TikTok-style micro-reels — paired with a swipeable vertical feed, karaoke captions, HLS streaming, and full engagement tracking. Built end-to-end in 10 days.

Product Engineer10 daysAI · EdTech · Full-Stack

≥ 5

Reels auto-generated per course — zero manual video editing required

< 100ms

Feed transition time via CSS scroll-snap running on compositor thread

12 / 12

Playwright tests passed across feed, player, and engagement tracking

Executive Summary

Turning idle course content into a discovery engine.

KnowledgeCity's library spans thousands of courses, but course discovery relied entirely on search and browse. Learners who didn't already know what they were looking for rarely found something new. Long-form video required upfront commitment, and the mobile experience had no equivalent of the casual, scroll-driven engagement patterns learners used everywhere else.

I designed and built an end-to-end system: an AI pipeline that processes course transcripts through a three-stage segmentation → scripting → QC workflow, producing 30–90 second micro-reels with structured Hook / Core / Takeaway scripts. The consumer side is a TikTok-style vertical feed with CSS scroll-snap transitions, karaoke-style captions, HLS adaptive streaming, and a Mixpanel-backed engagement event layer with offline queuing.

The feature shipped two tickets to production (PORTAL-2419, PORTAL-2420) within 10 days, with a third (PORTAL-2418) in experimental testing. The implementation exceeded the original Jira spec with three unrequested additions: a TextReelPlayer for courses without video, a Web Audio API lo-fi beat engine, and deep-link support for reel permalinks.

Project Details

Timeline
10 days (April 14–24, 2026)
Platform
KnowledgeCity Portal — Enterprise SaaS LMS, B2B, multi-tenant
Scope
AI pipeline · Swipeable feed · Reel player · Engagement tracking · Standalone demo
Role
Product Engineer — solo, end-to-end
Stack
SvelteKit (KC), Next.js + FastAPI (demo), GPT-4o, hls.js, Playwright
Delivered
PORTAL-2418 (experimental) · PORTAL-2419 + PORTAL-2420 (production)

What Changed

Dimension

Before

After

Reel content creation

Manual video editing — weeks per course, not scalable

AI pipeline generates ≥ 5 reels per course in < 10 minutes

Feed transition performance

No short-form feed — learners had no discovery surface

< 100ms transitions via CSS scroll-snap (compositor thread, zero JS)

Caption accessibility

Not supported in short-form context

Karaoke-style word-by-word captions — WCAG 2.1 AA compliant

Engagement data

No per-reel engagement instrumentation

4 event types tracked with 5s deduplication and offline queue

Courses without video

Would have been excluded from the reels feed

TextReelPlayer: animated slide-based player with ambient audio (beyond spec)

Test coverage

No tests — net-new feature surface

12 Playwright tests from Jira acceptance criteria — 12/12 passed

Engagement metrics are ongoing post-launch. Performance figures are from Playwright test runs and browser DevTools measurement during development.

The Problem

"The course library is massive — but most learners never scroll past page two."

Synthesized from learner research and portal analytics review. Reflects a consistent discovery gap across the KnowledgeCity learner base.

Who it affected

Learners

Discovery required knowing what you were looking for.

  • Long-form video required upfront commitment — learners needed a reason to start before they had one.
  • Mobile browsing patterns had no equivalent to the casual, intent-free scroll that short-form content enables.
  • Learners in casual contexts (commute, break) had no lightweight entry point into the course library.
Administrators

Promoting new courses meant manual marketing effort.

  • No automated mechanism to surface course content — admins relied on email campaigns or featured banners.
  • Video previews were static thumbnails, not interactive — low conversion from course listing pages.
  • Creating short promotional clips required external video editing tools and dedicated effort per course.
Business

Engagement plateaued without a new discovery surface.

  • Completion rates are a key contract renewal metric for B2B LMS clients — flat engagement risked churn.
  • Competitors in consumer EdTech (Duolingo, Coursera) had invested in micro-content; B2B LMS had not.
  • Existing course library represented significant content investment with no short-form access layer.

AI Workflow

A three-stage pipeline from transcript to approved reel script.

Rather than generating reels from scratch, the AI pipeline treats existing course content as structured source material. Each transcript is analyzed for concept boundaries, rewritten into a learnable short-form format, and gated for quality before being surfaced.

01

Segmentation

GPT-4o-mini

The transcript is chunked and passed to a segmentation prompt that identifies 5–10 self-contained learning moments. Each segment is scored on density (concept richness) and clarity (explainability). Segments with a combined score below 12/20 are filtered before scripting begins.

Outputs

  • concept_title
  • type (concept | example | tip | mistake | summary)
  • hook_line
  • density_score + clarity_score
  • source_excerpt
02

Scripting

GPT-4o

Each approved segment is passed to a scripting prompt that rewrites it into a three-part micro-reel structure: Hook (first 5 seconds — one punchy sentence), Core (concept + concrete example + application), and Takeaway (memorable close + course CTA). Target: 150–188 words at 150 wpm = 60–75 seconds.

Outputs

  • hook
  • core
  • takeaway
  • estimated_duration_seconds
  • confidence_score
03

QC Gate

Rule-based

Scripts are filtered by a confidence threshold (0.75). Scripts derived from low-scoring segments that the segmenter borderline approved are flagged rather than discarded — available for human review. The pipeline returns separate approved and flagged arrays so editors can override without regenerating.

Outputs

  • approved[]
  • flagged[] for human review
  • total / approved / flagged counts
  • mock fallback when no API key

Prompt Design Principles

Second person only — "you", never third-person. Keeps reels direct and personal.

Max 12 words per sentence in scripts. Forces clarity, works muted.

No invented facts — pipeline is instructed to only use source transcript material.

[VERIFY] flag for any non-standard claims — surfaces edge cases without breaking the pipeline.

Cheap model (gpt-4o-mini) for segmentation, full model (gpt-4o) for scripting — cost-conscious design.

Key Features

Six systems that had to work together.

Each feature was a separate Jira ticket with its own acceptance criteria. The feed, player, and engagement layer are independently deployable — and were separately tested.

PORTAL-2418

Swipeable Reels Feed

CSS scroll-snap-type: y mandatory drives the feed — no JS scroll listener, no frame budget cost. IntersectionObserver (threshold: 0.6) detects the active reel and triggers play/pause. Infinite scroll activates when two reels from the end. A ?reel= query param enables deep-links from any surface.

scroll-snap + IntersectionObserver(0.6) + Svelte writable store

PORTAL-2419

Reel Player with Karaoke Captions

Two player types: ReelPlayer streams HLS via video.js with VTT caption sync, mute toggle, progress bar, and "View Course" CTA. TextReelPlayer handles courses without video — animated slides driven by key_ideas arrays, same controls, matched layout. Caption preference persists across sessions via localStorage.

hls.js + VTT captions + animated slide fallback

PORTAL-2419

Web Audio Lo-Fi Beat Engine

TextReelPlayer includes a procedural audio system built with the Web Audio API — 90 BPM lo-fi beat with kick drum, snare, and hi-hats, plus an Am-F-C-G ambient chord progression processed through DynamicsCompressor. Toggleable per-user, respects the shared mute store. Built across 4 commits on April 22.

Web Audio API · OscillatorNode · DynamicsCompressor

PORTAL-2420

Engagement Event Tracking

Four events — reel_view_start, reel_view_complete (fires at ≥ 95% duration), reel_swiped_away, reel_course_clicked — are tracked with a 5-second deduplication window keyed by reelId:eventType. Events are queued in localStorage when offline and batch-flushed on reconnect via window.online.

Mixpanel + offline localStorage queue + auto-flush

Architecture

AI Reel Generation Pipeline

FastAPI backend with a three-stage GPT pipeline: segmentation (gpt-4o-mini) → scripting (gpt-4o) → QC gate (confidence ≥ 0.75). Gracefully degrades to deterministic mock output when no API key is configured — enabling full frontend development and testing without live AI calls.

FastAPI · GPT-4o · SQLAlchemy async · SQLite

Architecture

KC API Integration Layer

A transformer function maps KnowledgeCity course data (title, tagline, description, skill_level, lessons_count) to the Reel interface — enabling the feed to populate from the live KC course catalog. Falls back to curated dummy reels on any error (CORS, 498, 499) without a redirect.

courseToReel() transformer · graceful degradation

Delivery

From planning doc to production in 10 days.

Every commit on branch PORTAL-2418 corresponds to a specific feature or refinement. The implementation started from an AI-generated planning document and iterated daily with browser verification after each session.

Jira Tickets Delivered

PORTAL-2418Swipeable Reels Feed ComponentTesting in Experimental
PORTAL-2419Reel Player (HLS, Captions, CTA)Deployed to Production
PORTAL-2420Engagement Event TrackingDeployed to Production

Commit Timeline — PORTAL-2418

Apr 14e1f8ce8

Full initial implementation — interfaces, API, store, engagement, ReelsFeed, ReelPlayer, ReelCard, skeleton

Apr 16209f07d

Refine Course Reels UI to match Recently Viewed design (PRs #6557 and #6558 merged)

Apr 20614ee85

Replace ki-icons with inline SVGs; remove swipe-up hint (icons not in KC icon library)

Apr 22044e147

Add TextReelPlayer with animated slides for text-based reels

Apr 2243d20af

TextReelPlayer: match ReelPlayer UI + Web Audio API ambient chord progression added

Apr 227ab99c8

Replace ambient pads with lo-fi beat engine (90 BPM, Am-F-C-G, DynamicsCompressor)

Apr 2236e400f

generateKeyIdeas() for every course — all reels use TextReelPlayer dynamically

Apr 22e7ee6db

Share mute state across all reels via reelsMuteStore (svelte-local-storage-store)

Apr 24a4083a2

Refactor: make feed fully dynamic — remove hardcoded course IDs

Apr 2465922a7

Deep-link to specific reel from home page preview (?reel= query param)

Playwright Test Suite

12 / 12 Passed

1

Feed renders 3 reel cards from mocked API

PASS
2

Title + course name display correctly

PASS
3

Duration badge format (0:45, 1:00, 1:30)

PASS
4

Progress bar element present in DOM

PASS
5

Mute toggle: aria-label changes Unmute to Mute

PASS
6

Caption toggle persisted to localStorage (kc_reels_captions)

PASS
7

View Course CTA button present and labelled

PASS
8

CSS scroll-snap transitions to reel 2

PASS
9

Empty state renders when API returns no reels

PASS
10

Error state + retry button on API failure

PASS
11

Retry button reloads feed

PASS
12

/en/reels accessible when logged in (no auth redirect)

PASS

Beyond Original Spec

4 unrequested additions.

+

TextReelPlayer

Animated slide-based reel player for courses without video — same controls, matched layout, Svelte component with blob backgrounds and slide transitions.

+

Web Audio lo-fi engine

90 BPM lo-fi beat (Am-F-C-G) with kick, snare, and hi-hats via Web Audio API OscillatorNode + DynamicsCompressor. Toggleable per-user.

+

Shared mute state

reelsMuteStore via svelte-local-storage-store — mute preference persists across all reel types and page reloads, respects browser autoplay policy.

+

Deep-link support

?reel= query param reads initialReelId on mount and scrolls to the target card — enables direct links from home page previews and external surfaces.