Advanced
Thumbnail Strategy
How ytcn loads thumbnails and why it matters for perceived performance.
Three-phase lifecycle
ytcn uses a three-phase state machine to manage the player lifecycle. This eliminates the black flash that occurs when loading YouTube iframes directly.
| Phase | What's visible | Duration |
|---|---|---|
| thumbnail | CDN thumbnail + play button overlay | < 100ms to first paint |
| loading | Blurred thumbnail + spinner | 1–3s (iframe initialization) |
| ready | Live video with custom controls | Rest of session |
Thumbnail probing
The useThumbnail hook probes YouTube's CDN in priority order. It uses imperative Image() objects (not fetch) to avoid CORS issues.
thumbnail probing order
Priority 1: https://img.youtube.com/vi/{id}/maxresdefault.jpg (1280×720)
Priority 2: https://img.youtube.com/vi/{id}/hqdefault.jpg (480×360)
Priority 3: https://img.youtube.com/vi/{id}/mqdefault.jpg (320×180)
Priority 4: https://img.youtube.com/vi/{id}/default.jpg (120×90)Why not just use maxresdefault?
Not all videos have a maxresdefault thumbnail. Videos uploaded in standard definition (480p or below) only have the lower-resolution options. The probing strategy ensures ytcn always shows the best available thumbnail without requiring the user to specify a URL.
Performance impact
Loading a thumbnail from YouTube's CDN is dramatically faster than loading the full iframe:
- •Thumbnail: ~20KB image, loads in under 100ms on broadband
- •YouTube iframe: ~500KB+ of JavaScript, 1–3 seconds to initialize
Custom thumbnails
If you want to use your own thumbnails instead of YouTube's CDN, bypass the hook and pass a URL directly:
custom-thumbnail.tsx
// Skip useThumbnail and provide your own
<img
src="/my-custom-thumbnail.jpg"
alt="Video thumbnail"
className="absolute inset-0 w-full h-full object-cover"
/>