One Video Turned Into a Course Platform

Someone asked for a single presenter video. Five months later it teaches, answers questions out loud, and knows exactly what it knows. Here is how it grew.

A single video frame growing outward into a structured course system

Someone handed me an archive of lecture recordings and asked for one presenter video. A person on screen delivering the material, so their students could watch something built for them.

I made the video. Then I got curious about what the rest of it would take.

Five months and eighty commits later, that one video has become a course platform with a tutor that answers questions out loud, grounded in the chapter the student is actually sitting in. This is the part I enjoy most about this work: you solve the thing in front of you, and the solving shows you the next thing.

Story

The short version of how a course tutor stays trustworthy: store the lesson as structured blocks rather than a page of text, then let the tutor read those same blocks. What the student is taught and what the tutor knows are the same artifact, read twice. They cannot drift apart.

The material was richer than the brief

The brief said video. The archive said something more interesting.

A textbook, as raw text and scanned pages. Three lecture recordings per chapter. Slide decks. And a question bank exported from a form, which turned out to be the most valuable thing in the box, because it showed what students had actually found hard rather than what a syllabus assumed they would.

Four formats, four different shapes, all describing the same chapter from different angles. Once you can see that, making a single video out of it feels like using a very small part of what you have.

Three extraction paths leaving the same handover and rejoining at analysis: audio through transcription, lecture video through keyframes, decks and workbook through parsing.
Three extraction paths leaving the same handover and rejoining at analysis: audio through transcription, lecture video through keyframes, decks and workbook through parsing.

FFmpeg pulls keyframes and audio out of the recordings. Whisper transcribes locally, which I like for a reason beyond cost: the client’s material never leaves my machine during the noisiest part of the process. python-pptx and openpyxl read the decks and the workbook. Claude maps the topics against the syllabus, then drafts the narration and the slide specifications.

What comes out is not a script. It is a structure: what this chapter teaches, in what order, with which worked examples and which questions.

The synthesis step is the one people assume is more complicated than it is. Four sources have to become one coherent chapter, and the obvious instinct is to chop everything into fragments, embed them, and retrieve the relevant pieces on demand.

I did not do that, and I would argue against it.

Deciding what a chapter teaches is a question of proportion. Which idea deserves eight minutes and which deserves a sentence. What the lecturer labored that the textbook covers in a line. Which misconception shows up repeatedly in the question bank and therefore needs its own worked example. None of those judgments can be made from fragments, because the whole point is comparing one part against every other part.

So all of it goes in at once. The full transcript, the full deck, the whole question bank, held together in a single pass. That is what long context is genuinely good at, and it is why the analysis reads like someone who watched the lecture rather than someone who skimmed an index.

Then the interesting decision

The obvious move at that point is to render the video, publish it, and call the job done.

The better move, it turned out, was to decide how a lesson gets stored before deciding how it gets shown.

The script forks. One path becomes video, the other becomes structured lesson blocks, and the playback identifier is what brings them back together.
The script forks. One path becomes video, the other becomes structured lesson blocks, and the playback identifier is what brings them back together.

Every lesson is a list of typed content blocks. A heading is a heading. A worked example knows it is a worked example. A quiz carries its options, its correct answer, and the explanation for each wrong one. Nothing is a wall of markup with meaning buried inside it.

That choice paid for itself three times over, and I only planned for the first.

It made the player straightforward, because rendering a known set of block types is easy. It made the content portable, because structured data travels and formatted HTML does not. And it made the tutor possible, which I had not thought about at all when I chose it.

The tutor reads the lesson itself

Here is the part I would defend hardest if anyone asked.

The tutor does not have a separate summary of the course written for it. It reads the lesson’s own content blocks, flattened back into plain text. Quizzes included, which matters more than it sounds, because the worked numbers in this chapter live in the feedback on quiz options rather than in the prose.

So when a student asks about the figures in a worked example, the tutor is reading the same thing the student is looking at. Update the lesson and the tutor updates with it. There is no second source to keep in step.

Two entry paths with different authentication, converging on one grounding core. Everything in orange is code I wrote rather than a service I bought.
Two entry paths with different authentication, converging on one grounding core. Everything in orange is code I wrote rather than a service I bought.

It also knows the edge of what it knows. When a question falls outside the chapter, the tutor emits a token, and the server swaps that token for a clear, friendly “that is not in this chapter” before a single word reaches the student. The model decides when to reach for it. The server guarantees that an admission and a guess can never share a reply.

One path through the tutor. The gate sits between the model and the student, so nothing reaches a learner without passing it.
One path through the tutor. The gate sits between the model and the student, so nothing reaches a learner without passing it.

The part I did not expect: every one of those moments is logged. A student asking something reasonable that the material does not cover is not a problem to suppress, it is a note for the next revision of the chapter. A safety mechanism turned into a curriculum tool.

Giving it a face

Text tutoring worked. Then I wanted to see the thing talk.

Putting a video avatar in front of the same tutor sounds like a front-end job and is genuinely not. The avatar platform runs its own agent loop, and to point it at your own model you hand it a configuration where the address is fixed at setup time, long before any student exists.

Which means there is nowhere to put a per-student token.

The answer was to let the two paths differ and keep the brain identical. My own player talks to the tutor with a normal session. The avatar platform talks to the same tutor with its own credential and the lesson named in the address. Two front doors, different locks, one grounding core behind both, and no caller anywhere allowed to supply its own instructions.

That is the most portable idea in the whole build. Anyone wiring a custom model into someone else’s agent platform meets the same wall, and the shape of the answer is always the same: put the grounding in one place and let the entry points be different.

Streaming turned out to matter more than I assumed, too. A complete answer takes a few seconds to write, and a talking avatar needs to start speaking well before that. Translating the model’s output into chunks the platform can consume as they arrive is what makes the difference between a conversation and a pause.

Two jobs that look like one

The distinction I keep coming back to is that reading a corpus and searching one are different jobs, and they want different tools.

Building a lesson is a reading job, which is why nothing in the authoring pipeline is chunked. Answering a student turns out to be a reading job too, at least at this size. A chapter is about thirteen thousand tokens, which fits in context with room to spare, so the tutor reads all of it on every question and caching keeps that at roughly two hundredths of a penny a time. No similarity tuning, no index to keep in step with the content.

Searching is the other job, and that is where I do reach for retrieval. I keep a vector index over forty-three documents of my own: proposals, research, production notes, the scripts already written. When I need to find where I said something six weeks ago, that is retrieval doing exactly what it is good at.

The part I find genuinely interesting is knowing when the tutor crosses over. One chapter fits comfortably. A full subject at twenty-six chapters is around a third of a million tokens, and re-reading twenty-five irrelevant chapters for every question stops making sense long before that.

The answer then is retrieval as a router rather than as a chunk fetcher. Let it choose which chapters are relevant, then load those chapters whole. The tutor keeps reading complete lessons instead of fragments, which is the property everything else rests on, and it scales to nine subjects without changing shape.

Sizing the solution to the problem you actually have, and knowing in advance what would change your mind, is most of the craft.

What it costs to run, and what stops it running away

Two things here cost money by the minute rather than by the month: a model answering a question, and a live video session.

Both are now capped. A learner gets a set number of video sessions an hour, and there is a hard ceiling per day across everyone, which is the number that actually bounds the bill. The check happens before a session is created, because the sensible place to stop a runaway is before the meter starts rather than after.

One detail I am quietly pleased with. If the counter itself cannot be read, the request is refused rather than allowed through. A limiter that fails open is decoration.

Everything else about the running cost is pleasantly boring. The tutor’s expensive part is the chapter it reads, and that gets cached, so a typical question lands at a fraction of a penny.

Where a person stays in the loop

Ten of the sixteen steps in this pipeline have a person in them, and that is a design decision rather than a gap waiting to be closed.

Someone decides where a topic starts and stops. Someone decides what to cut from a two-hour lecture and what deserves a worked example. Someone reads the draft narration and judges whether it teaches or merely covers. The machine does the extraction and the delivery, which is exactly what machines are good at. The judgment stays human.

For anything exam-critical, judgment alone is not the whole answer either. Subject-matter verification belongs with people who hold the qualification, which is why the design routes it to the client’s own tutors rather than to me. Fluent and correct are different properties, and only one of them can be checked by the person who wrote the words.

Eighty commits, and counting

80 commits · March to August
March
The platform itself, then auth, progress tracking and a structured content system
March
Multi-course schema, and the first chapter built out end to end
March
Video player, chat logging, quiz tracking
March
An admin dashboard, so the numbers were visible rather than guessed at
April
Admin login, transcript panel, demo access, page-view tracking
April
Enrolment gating, payment scaffolding, and room for 44 more courses
May
Certificates on completion, downloadable resources
June
Session replay, branding, playback polish
July
Student dashboard and the full 26-chapter structure
July
The tutor grounded in real lesson content
August
The tutor given a face, live on the site
August
Docked into the player, then made expandable
One video, five months, and a platform that teaches back. Highlighted rows are the moments it became something new.

Five months from a request for one video to a platform that teaches, tracks, certifies and answers back.

None of it came from a masterplan. Each piece came from finishing the previous piece and seeing what it made possible. The content model made the tutor possible. The tutor made the avatar worth doing. The avatar made the panel too small, so this week it learned to expand.

That is the loop I keep coming back to, and the reason this work is a pleasure rather than a task. You build the thing in front of you properly, and it hands you the next thing.

Want help building systems like this for your organization?

See how I could build this for your material
Benedict Rinne

Benedict Rinne, M.Ed.

Founder of KAIAK. Helping international school leaders simplify operations with AI. Connect on LinkedIn

Want help building systems like this?

We help school leaders automate the chaos and get their time back.

Book a callAI toolkit, by email