Skip to main content

Building Fokus: Revolutionizing Short-Form Video Content

00:05:05:99

From Idea to Reality: The Birth of Fokus 🚀

You know that feeling when you watch a YouTube video and think "this would make an amazing short"? That's exactly where Fokus started. My friend and I were discussing how time-consuming it is for creators to repurpose their long-form content into shorts for platforms like TikTok, Instagram Reels, and YouTube Shorts. We thought: "What if we could automate this?"

That's how we started building Fokus, a platform that not only identifies the most engaging moments in YouTube videos but also adds customizable, dynamic captions that make your shorts stand out. Let me take you through our technical journey.

Technical Stack: Why We Chose What We Chose 🛠️

The Foundation: Next.js + shadcn/ui

We built Fokus using Next.js 13 (with the app router) and shadcn/ui components. Here's why:

typescript
// pages/app/dashboard/page.tsx
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"

export default function Dashboard() {
  return (
    <Card className="p-6">
      <h1 className="text-3xl font-bold">Your Videos</h1>
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        {/* Video grid implementation */}
      </div>
    </Card>
  )
}

Using shadcn/ui has been a game-changer for us. Instead of building everything from scratch, we could focus on what makes Fokus unique - the video processing and caption customization features.

Database Architecture with Prisma ⚡

One of our early decisions was using Prisma with our own database service. Here's a simplified version of our schema:

typescript
// prisma/schema.prisma
model Video {
  id            String   @id @default(cuid())
  youtubeUrl    String
  timestamps    Timestamp[]
  captions      Caption[]
  b_roll        B_Roll[]
  scheduledUploads ScheduledUpload[]
  createdAt     DateTime @default(now())
}

model Caption {
  id            String   @id @default(cuid())
  text          String
  style         Json
  videoId       String
  video         Video    @relation(fields: [videoId], references: [id])
}

model B_Roll {
  id            String   @id @default(cuid())
  timestamp     Float
  category      String
  sourceUrl     String
  videoId       String
  video         Video    @relation(fields: [videoId], references: [id])
}

model ScheduledUpload {
  id            String   @id @default(cuid())
  videoId       String
  platform      String
  scheduledFor  DateTime
  status        String
  video         Video    @relation(fields: [videoId], references: [id])
}

Core Features and Implementation ✨

Smart Moment Detection 🎯

One of the coolest features we built is our smart moment detection system. It analyzes factors like:

  • Speech density and pace
  • Musical transitions
  • Scene changes
  • Audience retention data (when available)
typescript
interface DetectionResult {
  timestamp: number;
  confidence: number;
  type: 'speech' | 'music' | 'scene_change';
}

async function analyzeVideo(videoId: string): Promise<DetectionResult[]> {
  // Our actual implementation is more complex, but you get the idea
  const video = await prisma.video.findUnique({
    where: { id: videoId },
    include: { timestamps: true }
  });
  
  // Analysis logic here
  return results;
}

Automated B-Roll Integration 🎬

One of our most powerful features is the automated B-roll system. It intelligently selects and inserts relevant B-roll footage based on the video content:

typescript
interface B_RollMatch {
  timestamp: number;
  keywords: string[];
  context: string;
}

async function suggestB_Roll(videoId: string): Promise<B_RollMatch[]> {
  const video = await prisma.video.findUnique({
    where: { id: videoId },
    include: { captions: true }
  });
  
  // AI-powered content analysis to identify B-roll opportunities
  const contentAnalysis = await analyzeVideoContent(video);
  
  // Match with our B-roll library
  const suggestions = await matchB_RollContent(contentAnalysis);
  
  return suggestions;
}

Caption Customization 🎨

We wanted to make caption customization both powerful and intuitive. Users can:

  • Change fonts, colors, and animations
  • Add emojis and effects
  • Adjust timing and positioning
  • Edit the actual text for better impact

Smart Upload Scheduling 📅

We implemented a sophisticated scheduling system that allows creators to plan their content distribution across multiple platforms:

typescript
interface UploadSchedule {
  videoId: string;
  platform: 'youtube_shorts' | 'tiktok' | 'instagram';
  scheduledTime: Date;
  options: UploadOptions;
}

async function scheduleUpload(schedule: UploadSchedule) {
  // Create scheduled upload record
  const scheduledUpload = await prisma.scheduledUpload.create({
    data: {
      videoId: schedule.videoId,
      platform: schedule.platform,
      scheduledFor: schedule.scheduledTime,
      status: 'pending'
    }
  });
  
  // Add to upload queue
  await uploadQueue.add({
    uploadId: scheduledUpload.id,
    executeAt: schedule.scheduledTime
  });
}

Challenges We Faced 💪

Performance Optimization

Processing video data can be heavy. We implemented a queue system using Bull to handle video processing:

typescript
import Queue from 'bull';

const videoQueue = new Queue('video-processing', {
  redis: process.env.REDIS_URL
});

videoQueue.process(async (job) => {
  const { videoId } = job.data;
  // Process video and generate timestamps
});

Real-time Preview System

Getting the preview system right was tricky. We needed to balance performance with accuracy:

typescript
// components/PreviewPlayer.tsx
export function PreviewPlayer({ videoId, captions, b_roll }) {
  const [currentTime, setCurrentTime] = useState(0);
  
  const visibleCaptions = useMemo(() => 
    captions.filter(cap => 
      cap.startTime <= currentTime && cap.endTime >= currentTime
    ),
    [captions, currentTime]
  );

  const currentB_Roll = useMemo(() =>
    b_roll.find(clip =>
      clip.timestamp <= currentTime && clip.timestamp + clip.duration >= currentTime
    ),
    [b_roll, currentTime]
  );

  return (
    <div className="relative">
      <VideoPlayer 
        src={`/api/videos/${videoId}`}
        onTimeUpdate={setCurrentTime}
      />
      <CaptionOverlay captions={visibleCaptions} />
      {currentB_Roll && <B_RollOverlay clip={currentB_Roll} />}
    </div>
  );
}

What's Next for Fokus? 🔮

We're working on some exciting features:

  • Auto-translation into multiple languages
  • Advanced AI-powered moment detection
  • Custom animation builder
  • Analytics dashboard for tracking performance
  • Batch processing for multiple videos
  • Enhanced B-roll library with AI-powered categorization
  • Cross-platform analytics for scheduled uploads

Lessons Learned 📚

Building Fokus has taught us a lot:

  1. Start with a solid architecture, but be ready to adapt
  2. User feedback is gold - we've changed several features based on early user testing
  3. Performance optimization should be considered from day one
  4. Building with friends is fun, but clear communication is key
  5. Automation should enhance creativity, not replace it

Conclusion 🎬

Fokus represents our vision for the future of content creation, and we're excited to be actively building it. While still in development, it's already shaping up to be more than just a side project - it's our attempt to solve a real problem for content creators. By automating tedious tasks like B-roll selection and upload scheduling, we aim to help creators focus on what they do best: creating amazing content. We're currently in the final stages of development, continuously refining features based on early testing and feedback from fellow developers. We can't wait to share it with the creator community and see how they'll use it to transform their content creation workflow.