An interactive deep-dive into the app that turns hour-long YouTube videos into a structured learning workspace — with AI highlight reels, timestamped answers, and personal notes.
A film editor's cutting room — you give them raw footage, they find the best moments, cut them together, and hand you a highlight reel.
LongCut turns long YouTube videos into a learning workspace. You paste a URL, and AI generates highlight reels, summaries, chat Q&A, and a place for your personal notes. It's like having an AI study buddy that watches the video for you and picks out the good parts.
AI picks the best moments from the video. You play them in sequence like a curated playlist of the most valuable parts.
Ask questions about the video and get answers with timestamp citations — so you can jump to the exact moment.
Synced with the video player. Click any sentence to jump to that moment in the video.
Save quotes from the transcript, chat answers, or write your own thoughts. All linked to video timestamps.
Smart mode picks quality highlights. Fast mode generates topics quickly. You choose the tradeoff between depth and speed.
Here's what happens behind the scenes when you paste a YouTube URL:
The input field accepts any YouTube URL format — standard, shortened, or embedded.
It pulls the unique video ID (the part after "v=" in a YouTube link) and navigates you to the analysis workspace.
A third-party service that reliably extracts YouTube transcripts, including auto-generated captions.
The transcript is chunked and run through a map-reduce pipeline — AI reads each chunk, then picks the overall best moments.
So the next time anyone visits the same video, the results are instant — no re-analysis needed.
Video player on the left with highlight reel cards below it. Tabbed panel on the right with summary, chat, transcript, and notes.
This is the function that runs when you click "Analyze":
const handleSubmit = useCallback(
(url: string) => {
const videoId = extractVideoId(url);
if (!videoId) {
toast.error("Please enter a valid YouTube URL");
return;
}
const params = new URLSearchParams();
params.set("url", url);
router.push(`/analyze/${videoId}?${params.toString()}`);
},
[router]
);
This useCallback wraps a function so React doesn't wastefully recreate it on every render.
When the user submits a URL, it first tries to extract the video ID (the unique part like "dQw4w9WgXcQ").
If the URL is invalid, show a toast error notification and stop.
Otherwise, build a URL with the video ID and the original URL as a parameter.
Then use the router to navigate the user to the analysis workspace at /analyze/[videoId].
The video ID lives in the URL (/analyze/abc123), not in hidden state. This means you can bookmark, share, or refresh an analysis page and it still works. When you tell AI to build a web app, saying "put the key data in the URL" is called "URL-driven state" — and it's a professional pattern.
You want to add support for Vimeo URLs alongside YouTube. Where in the code would you start?
A newsroom — editor-in-chief (page.tsx), reporters in the field (API routes), researchers in the library (lib/), and the graphics department (components/).
Every file in LongCut has a role, like staff members in a newsroom. Here are the five main departments:
The Pages — what users see and interact with. The landing page and the analysis workspace.
The API Routes — backend logic that talks to AI, databases, and external services.
The Library — shared logic used by many parts of the app: AI clients, security, database helpers, validation.
The UI Components — reusable pieces: chat panel, highlights, notes, transcript viewer.
The Shared Memory — auth state and playback state shared across components, so they stay in sync.
Here's the actual structure of the LongCut codebase. Each file has one clear job:
This is the main page you see after pasting a URL — a two-column layout built from specialized components:
return (
<div className="grid grid-cols-[1fr_400px] h-screen">
{/* Left column: YouTube player + highlights */}
<YouTubePlayer videoId={videoId} />
<HighlightsPanel topics={topics} selectedTopic={selectedTopic} />
{/* Right column: tabs */}
<RightColumnTabs
transcript={transcript}
topics={topics}
notes={notes}
showChatTab={showChatTab}
/>
</div>
);
The workspace is a two-column grid. Left side takes all remaining space; right side is a fixed 400px.
Left column: the YouTube video player and highlight reel cards below it.
Right column: a tabbed panel with four views — transcript, AI chat, and notes.
Each component is a self-contained specialist that gets the data it needs through props.
Instead of one massive file, the workspace is built from small, focused components. Each one does one thing well. When you tell AI to build a complex page, say "break it into components" — this is exactly what you mean.
A user reports the chat tab isn't loading. Based on the file structure, where would you tell AI to look first?
A book club where each member reads a different chapter — then a moderator picks the overall best moments from everyone's notes.
LongCut doesn't just throw the entire transcript at an AI and hope for the best. It uses a structured two-stage process called map-reduce:
Thousands of lines of text from the video — far too much for any AI to process at once.
The transcript is sliced into digestible pieces with 45-second overlaps at the edges.
Each chunk is sent to AI independently. It extracts up to 2 candidate topics per chunk — the best moments it found.
AI reviews ALL candidates from ALL chunks and selects the top N — ranked by quality and insight.
Each selected topic gets timestamps, descriptions, and key quotes — ready to play as a highlight reel.
This is the function that slices the transcript into pieces the AI can handle:
function chunkTranscript(
segments: TranscriptSegment[],
chunkDurationSeconds: number,
overlapSeconds: number
): TranscriptChunk[] {
const effectiveChunkDuration = Math.max(180, chunkDurationSeconds);
const effectiveOverlap = Math.min(
Math.max(overlapSeconds, 0),
Math.floor(effectiveChunkDuration / 2)
);
const step = Math.max(60, effectiveChunkDuration - effectiveOverlap);
This function takes three inputs: the transcript segments, how long each chunk should be (in seconds), and how much overlap between chunks.
It enforces a minimum chunk size of 180 seconds (3 minutes). Even if you ask for smaller chunks, it won't go below this.
The overlap can't be negative, and can't be more than half the chunk duration (that would make the chunks overlap more than they cover new ground).
The "step" is how far to advance between chunks. With 5-minute chunks and 45-second overlap, each step moves about 4 minutes and 15 seconds forward — like how book chapters sometimes recap the end of the last chapter.
AI models have a limit on how much text they can process at once (called a context window). Chunking is how you handle content that's longer than that limit. When you ask AI to process a long document, saying "chunk it with overlap" is the professional way to avoid missing context at the edges.
LongCut doesn't lock itself to one AI provider. It supports two, and they're interchangeable:
Default provider. Uses grok-4-1-fast-non-reasoning. Sanitizes Zod schemas for compatibility.
Backup provider. Cascade strategy: tries lite, then flash, then pro. Built-in retry for rate limits.
export async function generateAIResponse(
prompt: string,
options: GenerateAIOptions = {}
): Promise<string> {
const providerParams = coerceProviderParams(prompt, options);
const result = await generateStructuredContent(providerParams);
return result.content;
}
This is the single entry point for ALL AI calls in the app. No matter which provider is configured (Grok or Gemini), this function handles it.
It converts the request into the right format for whichever provider is active, sends it, and returns the result.
The rest of the app never needs to know which AI is being used — it just calls this one function.
Wrapping different services behind a single interface is called the adapter pattern. It means you can swap Grok for Gemini (or a future Claude integration) by changing ONE config variable, not rewriting every file. When you tell AI "make the AI provider swappable," this is what you want.
xAI's API goes down. How does LongCut handle this?
An airport control tower tracking a flight — each step has checkpoints, handoffs between departments, and a tracking system that knows where your request is at every moment.
Follow the exact journey of your analysis request through the system:
Here's what it would sound like if the four parts of the system were texting each other during a video analysis:
Before doing any expensive AI work, the app checks if someone already analyzed this video:
if (!forceRegenerate) {
const { data } = await supabase
.from('video_analyses')
.select('*')
.eq('youtube_id', videoId)
.single();
cachedVideo = data ?? null;
}
Unless the user specifically asked to re-analyze (forceRegenerate), check the cache first.
Supabase queries the video_analyses table: "Find a row where youtube_id matches this video."
If found, skip the AI entirely and return the cached results. This saves money (AI calls cost real money) and makes repeat visits instant.
Notice the order of operations here — it's intentional and important:
// 4. Save to database (BEFORE consuming credits)
const saveResult = await saveVideoAnalysisWithRetry(supabase, {...});
// 5. Consume credit only if save succeeded
if (saveResult.success && user && !unlimitedAccess) {
await consumeVideoCreditAtomic({...});
}
First, save the AI's analysis results to the database. This is the valuable output the user is paying for.
Only THEN, if the save succeeded AND the user is logged in AND they don't have unlimited access, deduct one credit from their account.
This ordering is a clever trick. If the save fails, the user doesn't lose a credit for nothing. It's like paying for a meal only after it's on your table, not when you order.
In production apps, the ORDER you do things in can prevent data corruption. "Save first, charge second" means a failed save doesn't cost the user. This is related to atomic operations. When reviewing AI-generated code, check: what happens if step 3 fails after step 2 already ran?
The AI generates great topics but the database save fails. Does the user lose a credit?
Airport security — multiple checkpoints, each checking for something specific. Miss any one and you don't get through.
LongCut doesn't rely on a single lock. It uses layered defense — multiple independent checks that each catch different types of threats:
Every state-changing request carries a token. Prevents other websites from tricking your browser into making requests on your behalf.
Caps how many requests a user can make per minute. Prevents abuse and keeps AI costs under control.
Some routes require a logged-in user. Protects personal data and paid features like note saving and video analysis.
Tells the browser which scripts, images, and connections are allowed. Blocks injection attacks at the browser level.
Instead of adding security checks inside every handler, LongCut wraps them in a security layer:
export function withSecurity(
handler: (req: NextRequest) => Promise<NextResponse>,
config: SecurityMiddlewareConfig = {}
) {
return async function securedHandler(req: NextRequest) {
if (config.allowedMethods && !config.allowedMethods.includes(req.method)) {
return NextResponse.json({ error: 'Method not allowed' }, { status: 405 });
}
if (config.requireAuth) {
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: 'Authentication required' }, { status: 401 });
}
}
if (config.rateLimit) {
const result = await RateLimiter.check(req.url, config.rateLimit);
if (!result.allowed) {
return NextResponse.json({ error: 'Rate limit exceeded' }, { status: 429 });
}
}
return handler(req);
};
}
This is a wrapper function — it takes your API handler and wraps it in security checks.
Before your code even runs, it checks: (1) Is this HTTP method allowed? (2) Is the user logged in (if required)? (3) Has the user exceeded their rate limit?
Each check returns a specific status code: 405 for wrong method, 401 for unauthenticated, 429 for rate-limited.
Your actual handler only runs if ALL checks pass. The rest of the app's code never needs to worry about these security concerns.
Instead of configuring security from scratch for every route, LongCut provides three presets — like difficulty levels:
Good security isn't one big wall — it's multiple layers. If CSRF fails, rate limiting catches abuse. If rate limiting is bypassed, auth blocks unauthorized access. When you tell AI to "add security," ask for LAYERS, not just one check.
You're building an app with a "delete account" button. Which security preset would you use for that API route?
A city map — you've explored individual buildings, now zoom out to see how the streets connect them and how traffic flows between districts.
Click any component to learn what it does. Four zones, from the user's browser to the data layer:
Five core tables power all of LongCut's features:
You've completed the full architecture tour. Here's what you're equipped to do:
You understand the full architecture — pages, API routes, lib, components, and contexts.
You know the adapter pattern. Just add a new provider in lib/ai-providers/ and update the config.
Pages for UI issues, api/ for backend issues, lib/ for shared logic. You know where to look.
Chunking with overlap, cache-before-charge, security presets, provider abstraction — you know the vocabulary.
Use LongCut's architecture as a blueprint: Next.js + React frontend, TypeScript throughout, serverless API routes, Supabase for data.
You want to add a "generate flashcards" feature. Based on the architecture, what files would you create or modify?