1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <title>IPTV Bridge â Cinema for your Stremio & Nuvio</title> 7 <meta name="description" content="Connect Xtream Codes or M3U IPTV to Stremio & Nuvio with TMDB matching, global search and clean categories. Serverless, free, Vercel-ready." /> 8 <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> 9
9<script src="https://cdn.tailwindcss.com"></script>
9 10 <link rel="preconnect" href="https://fonts.googleapis.com" /> 11 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 12 <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" /> 13
13<script src="https://unpkg.com/lucide@latest"></script>
13 14
14<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
14 15
15<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ScrollTrigger.min.js"></script>
15 16
16<script> 17 tailwind.config = { theme: { extend: { fontFamily: { 18 serif: ['"Instrument Serif"','serif'], sans: ['"Space Grotesk"','sans-serif'], mono: ['"JetBrains Mono"','monospace'] } } } }; 19 </script>
19 20 <link rel="stylesheet" href="/theme.css" /> 21</head> 22<body class="antialiased"> 23 <div class="grain"></div> 24 <div class="vignette"></div> 25 <div id="cursor"></div> 26 27 <!-- NAV --> 28 <nav id="nav" class="fixed top-0 inset-x-0 z-50 px-5 sm:px-10 py-4 flex items-center justify-between transition-all duration-300"> 29 <a href="/" class="flex items-center gap-2.5" data-cursor> 30 <img src="/logo.svg" class="w-7 h-7 rounded-lg" alt="IPTV Bridge" /> 31 <span class="font-sans font-semibold tracking-tight">IPTV Bridge</span> 32 </a> 33 <div class="hidden md:flex items-center gap-8 text-sm text-[var(--paper)]/70 font-sans"> 34 <a href="#how" class="ul" data-cursor>Method</a> 35 <a href="#features" class="ul" data-cursor>Features</a> 36 <a href="#stack" class="ul" data-cursor>Stack</a> 37 <a href="/docs" class="ul" data-cursor>Docs</a> 38 <a href="#faq" class="ul" data-cursor>FAQ</a> 39 </div> 40 <a href="/configure" class="text-sm font-semibold ember px-4 py-2 rounded-full font-sans inline-flex items-center gap-1.5 leading-none" data-cursor><span>Configure</span> <i data-lucide="arrow-right" class="w-3.5 h-3.5"></i></a> 41 </nav> 42 43 <!-- HERO --> 44 <header class="relative z-10 min-h-screen flex flex-col justify-center px-5 sm:px-10 pt-24 pb-16 overflow-hidden"> 45 <div class="max-w-[1400px] mx-auto w-full relative z-10"> 46 <div class="flex items-center gap-3 mb-8 flex-wrap"> 47 <span data-hero-tag class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)]">Serverless</span> 48 <span class="w-8 h-px bg-[var(--line)]"></span> 49 <span data-hero-tag class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)]">Stremio · Nuvio</span> 50 <span class="w-8 h-px bg-[var(--line)]"></span> 51 <span data-hero-tag class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)]">Free on Vercel</span> 52 </div> 53 54 <h1 class="display text-[16vw] sm:text-[12vw] lg:text-[10.5vw]"> 55 <span class="line-mask"><span data-hero-line>Turn your IPTV</span></span> 56 <span class="line-mask"><span data-hero-line>into a <span class="italic-accent">cinema.</span></span></span> 57 </h1> 58 59 <div class="mt-10 grid md:grid-cols-[1.4fr_1fr] gap-8 items-end"> 60 <p data-hero-sub class="text-lg sm:text-xl text-[var(--paper)]/70 max-w-xl leading-relaxed font-sans"> 61 Xtream Codes or an M3U link becomes organized catalogs, global search, and automatic TMDB matching â every film and show resolves straight to your own sources. 62 </p> 63 <div data-hero-cta class="flex flex-col sm:flex-row md:justify-end gap-3"> 64 <a href="/configure" class="ember px-7 py-4 rounded-full font-sans font-semibold text-sm inline-flex items-center justify-center gap-2 leading-none" data-magnetic data-cursor-big> 65 <span>Configure</span> <i data-lucide="arrow-up-right" class="w-4 h-4"></i> 66 </a> 67 <a href="#how" class="glass-btn px-7 py-4 rounded-full font-sans font-semibold text-sm inline-flex items-center justify-center gap-2 leading-none" data-cursor> 68 <span>The method</span> 69 </a> 70 </div> 71 </div> 72 </div> 73 74 <div data-hero-scroll class="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 text-[var(--muted)]"> 75 <span class="text-[10px] font-sans tracking-[0.3em] uppercase">Scroll</span> 76 <span class="w-px h-10 bg-gradient-to-b from-[var(--accent)] to-transparent"></span> 77 </div> 78 </header> 79 80 <!-- MARQUEE --> 81 <section class="relative z-10 border-y border-[var(--line)] py-6 overflow-hidden"> 82 <div id="marquee-track" class="marquee items-center gap-12"></div> 83 </section> 84 85 <!-- STATS --> 86 <section class="relative z-10 px-5 sm:px-10 py-20 border-b border-[var(--line)]"> 87 <div class="max-w-[1400px] mx-auto"> 88 <div class="grid grid-cols-2 lg:grid-cols-4 rounded-3xl overflow-hidden border border-[var(--line)] divide-x divide-y lg:divide-y-0 divide-[var(--line)]"> 89 <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor> 90 <div class="flex items-center gap-2 mb-5 text-[var(--muted)]"> 91 <i data-lucide="plug-zap" class="w-4 h-4"></i>
92 <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Inputs</span> 93 </div> 94 <p class="display text-6xl sm:text-7xl text-[var(--accent)] leading-none">2</p> 95 <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Provider formats</p> 96 <p class="text-xs text-[var(--muted)] font-sans mt-1">Xtream Codes & M3U / M3U8</p> 97 </div> 98 <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor> 99 <div class="flex items-center gap-2 mb-5 text-[var(--muted)]"> 100 <i data-lucide="layout-grid" class="w-4 h-4"></i> 101 <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Catalogs</span> 102 </div> 103 <p class="display text-6xl sm:text-7xl leading-none group-hover:text-[var(--accent)] transition-colors">3</p> 104 <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Content types</p> 105 <p class="text-xs text-[var(--muted)] font-sans mt-1">Live TV · Movies · Series</p> 106 </div> 107 <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor> 108 <div class="flex items-center gap-2 mb-5 text-[var(--muted)]"> 109 <i data-lucide="database" class="w-4 h-4"></i> 110 <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Infra</span> 111 </div> 112 <p class="display text-6xl sm:text-7xl leading-none group-hover:text-[var(--accent)] transition-colors">0</p> 113 <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Databases or servers</p> 114 <p class="text-xs text-[var(--muted)] font-sans mt-1">Fully stateless & serverless</p> 115 </div> 116 <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor> 117 <div class="flex items-center gap-2 mb-5 text-[var(--muted)]"> 118 <i data-lucide="wallet" class="w-4 h-4"></i> 119 <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Cost</span> 120 </div> 121 <p class="display text-6xl sm:text-7xl leading-none group-hover:text-[var(--accent)] transition-colors">$0</p> 122 <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Hosting on Vercel</p> 123 <p class="text-xs text-[var(--muted)] font-sans mt-1">Runs on the free tier</p> 124 </div> 125 </div> 126 </div> 127 </section> 128 129 <!-- PROVIDER FORMATS --> 130 <section class="relative z-10 px-5 sm:px-10 py-24 border-b border-[var(--line)]"> 131 <div class="max-w-[1400px] mx-auto"> 132 <div class="flex items-end justify-between mb-12 flex-wrap gap-4"> 133 <div> 134 <p class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-3" data-reveal>Two ways in</p> 135 <h2 class="display text-5xl sm:text-7xl" data-reveal>Bring your own source</h2> 136 </div> 137 <a href="/configure" class="ghost px-5 py-3 rounded-full font-sans text-sm flex items-center gap-2" data-cursor data-reveal> 138 Connect now <i data-lucide="arrow-up-right" class="w-4 h-4"></i> 139 </a> 140 </div> 141 142 <div class="grid md:grid-cols-2 gap-4"> 143 <div class="format-card group relative border border-[var(--line)] rounded-3xl p-7 sm:p-9 overflow-hidden" data-reveal data-cursor> 144 <div class="flex items-center justify-between mb-6"> 145 <div class="w-12 h-12 rounded-2xl bg-[rgba(255,94,43,0.1)] border border-[rgba(255,94,43,0.25)] grid place-items-center"> 146 <i data-lucide="key-round" class="w-5 h-5 text-[var(--accent)]"></i> 147 </div> 148 <span class="text-[11px] font-sans uppercase tracking-[0.2em] text-[var(--muted)] px-3 py-1 rounded-full border border-[var(--line)]">Recommended</span> 149 </div> 150 <h3 class="text-2xl font-sans font-semibold mb-2">Xtream Codes API</h3> 151 <p class="text-sm text-[var(--paper)]/60 font-sans leading-relaxed mb-6">Host, username and password. We pull live, VOD and series categories directly â the cleanest, richest experience.</p> 152 <ul class="space-y-2.5 text-sm font-sans"> 153 <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i>
153 Native category structure</li> 154 <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Per-episode series resolution</li> 155 <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Account status & expiry check</li> 156 </ul> 157 </div> 158 159 <div class="format-card group relative border border-[var(--line)] rounded-3xl p-7 sm:p-9 overflow-hidden" data-reveal data-cursor> 160 <div class="flex items-center justify-between mb-6"> 161 <div class="w-12 h-12 rounded-2xl bg-[rgba(244,240,232,0.05)] border border-[var(--line)] grid place-items-center"> 162 <i data-lucide="link-2" class="w-5 h-5 text-[var(--paper)]/80"></i> 163 </div> 164 <span class="text-[11px] font-sans uppercase tracking-[0.2em] text-[var(--muted)] px-3 py-1 rounded-full border border-[var(--line)]">Universal</span> 165 </div> 166 <h3 class="text-2xl font-sans font-semibold mb-2">M3U / M3U8 Playlist</h3> 167 <p class="text-sm text-[var(--paper)]/60 font-sans leading-relaxed mb-6">Any single playlist URL. We parse group titles, logos and TVG metadata, then organize everything automatically.</p> 168 <ul class="space-y-2.5 text-sm font-sans"> 169 <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Works with any provider</li> 170 <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Auto group & type detection</li> 171 <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Logo & metadata extraction</li> 172 </ul> 173 </div> 174 </div> 175 </div> 176 </section> 177 178 <!-- HOW / METHOD --> 179 <section id="how" class="relative z-10 px-5 sm:px-10 py-28 sm:py-40"> 180 <div class="max-w-[1400px] mx-auto"> 181 <div class="flex items-baseline justify-between mb-14 flex-wrap gap-4"> 182 <div> 183 <p class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-3" data-reveal>How it works</p> 184 <h2 class="display text-6xl sm:text-8xl" data-reveal>The method</h2> 185 </div> 186 <span class="text-sm font-sans text-[var(--muted)] max-w-xs" data-reveal>Three moving parts, one clean result inside your player.</span> 187 </div> 188 <div id="method-grid" class="grid md:grid-cols-3 gap-4"> 189 <div class="method-card group relative border border-[var(--line)] rounded-3xl p-8 sm:p-9 overflow-hidden"> 190 <div class="flex items-center justify-between mb-8"> 191 <span class="method-num display text-6xl text-[var(--paper)]/15 group-hover:text-[var(--accent)] transition-colors duration-500">01</span> 192 <i data-lucide="plug-zap" class="w-5 h-5 text-[var(--accent)]"></i> 193 </div> 194 <h3 class="text-2xl mb-3 font-sans font-semibold">Connect</h3> 195 <p class="text-[var(--paper)]/60 leading-relaxed font-sans text-sm">Drop in Xtream credentials or an M3U URL. We parse channels, movies and series in one pass and cache them warm.</p> 196 </div> 197 <div class="method-card group relative border border-[var(--line)] rounded-3xl p-8 sm:p-9 overflow-hidden"> 198 <div class="flex items-center justify-between mb-8"> 199 <span class="method-num display text-6xl text-[var(--paper)]/15 group-hover:text-[var(--accent)] transition-colors duration-500">02</span> 200 <i data-lucide="clapperboard" class="w-5 h-5 text-[var(--accent)]"></i> 201 </div> 202 <h3 class="text-2xl mb-3 font-sans font-semibold">Resolve</h3> 203 <p class="text-[var(--paper)]/60 leading-relaxed font-sans text-sm">Titles are cleaned of release tags and matched to TMDB â posters, years, ratings and IMDB/TMDB IDs all line up.</p> 204 </div> 205 <div class="method-card group relative border border-[var(--line)] rounded-3xl p-8 sm:p-9 overflow-hidden"> 206 <div class="flex items-center justify-between mb-8">
207 <span class="method-num display text-6xl text-[var(--paper)]/15 group-hover:text-[var(--accent)] transition-colors duration-500">03</span> 208 <i data-lucide="play" class="w-5 h-5 text-[var(--accent)]"></i> 209 </div> 210 <h3 class="text-2xl mb-3 font-sans font-semibold">Stream</h3> 211 <p class="text-[var(--paper)]/60 leading-relaxed font-sans text-sm">Search anything in Stremio or Nuvio and your own IPTV source appears as a playable stream. One tap, it plays.</p> 212 </div> 213 </div> 214 </div> 215 </section> 216 217 <!-- FEATURES --> 218 <section id="features" class="relative z-10 px-5 sm:px-10 py-20 border-t border-[var(--line)]"> 219 <div class="max-w-[1400px] mx-auto"> 220 <p class="text-sm font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-10" data-reveal>What you get</p> 221 <ul id="feature-list" class="divide-y divide-[var(--line)] overflow-hidden"> 222 <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="left" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">Clean categories</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Live, Movies & Series sorted into tidy catalogs.</span></li> 223 <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="right" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">Global search</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Find any title, stream from your provider.</span></li> 224 <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="left" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">TMDB matching</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Posters, ratings, IMDB & TMDB resolution.</span></li> 225 <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="right" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">Zero servers</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Credentials live in your link. Nothing stored.</span></li> 226 </ul> 227 </div> 228 </section> 229 230 <!-- ARCHITECTURE / STACK --> 231 <section id="stack" class="relative z-10 px-5 sm:px-10 py-20 border-t border-[var(--line)]"> 232 <div class="max-w-[1400px] mx-auto"> 233 <div class="flex items-center justify-between mb-12 flex-wrap gap-4"> 234 <div> 235 <p class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-3" data-reveal>Architecture</p> 236 <h2 class="display text-5xl sm:text-7xl" data-reveal>Under the hood</h2> 237 </div> 238 <a href="https://github.com/jozphe/IPTV-BRIDGE" target="_blank" rel="noreferrer" class="source-link" data-cursor data-reveal> 239 <span class="source-link-icon" aria-hidden="true"> 240 <svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> 241 <path d="M12 2C6.477 2 2 6.588 2 12.253c0 4.532 2.865 8.376 6.839 9.733.5.095.682-.222.682-.493 0-.244-.009-.889-.014-1.744-2.782.619-3.369-1.374-3.369-1.374-.455-1.184-1.11-1.499-1.11-1.499-.908-.637.069-.624.069-.624 1.003.073 1.531 1.056 1.531 1.056.892 1.567 2.341 1.114 2.91.852.091-.663.349-1.114.635-1.37-2.221-.259-4.556-1.139-4.556-5.067 0-1.119.39-2.034 1.029-2.751-.103-.259-.446-1.302.098-2.712 0 0 .84-.276 2.75 1.051A9.37 9.37 0 0 1 12 6.99
2411a9.36 9.36 0 0 1 2.504.346c1.909-1.327 2.748-1.051 2.748-1.051.546 1.41.202 2.453.1 2.712.64.717 1.028 1.632 1.028 2.751 0 3.938-2.339 4.805-4.567 5.058.359.317.679.944.679 1.903 0 1.373-.012 2.481-.012 2.819 0 .274.18.593.688.492C19.138 20.626 22 16.784 22 12.253 22 6.588 17.523 2 12 2Z"/> 242 </svg> 243 </span> 244 <span class="source-link-label">View source</span> 245 <i data-lucide="arrow-up-right" class="source-link-arrow"></i> 246 </a> 247 </div> 248 249 <!-- Horizontal signal flow with a travelling ember pulse --> 250 <div id="flow" class="relative mb-4 overflow-x-auto" data-reveal> 251 <div class="relative min-w-[720px] py-6"> 252 <span class="flow-line absolute left-[8%] right-[8%] top-1/2 h-px bg-[var(--line)]"></span> 253 <span class="flow-pulse absolute top-1/2 w-24 h-px"></span> 254 <div class="relative grid grid-cols-5"> 255 <div class="flow-node group flex flex-col items-center text-center px-2"> 256 <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="key-round" class="w-5 h-5 text-[var(--accent)]"></i></span> 257 <span class="text-[10px] font-mono text-[var(--muted)] mb-1">01</span> 258 <p class="font-sans font-semibold text-sm">Source</p> 259 <p class="text-[11px] text-[var(--muted)] font-sans">Xtream / M3U</p> 260 </div> 261 <div class="flow-node group flex flex-col items-center text-center px-2"> 262 <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="filter" class="w-5 h-5 text-[var(--accent)]"></i></span> 263 <span class="text-[10px] font-mono text-[var(--muted)] mb-1">02</span> 264 <p class="font-sans font-semibold text-sm">Parse & cache</p> 265 <p class="text-[11px] text-[var(--muted)] font-sans">Clean · warm TTL</p> 266 </div> 267 <div class="flow-node group flex flex-col items-center text-center px-2"> 268 <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="clapperboard" class="w-5 h-5 text-[var(--accent)]"></i></span> 269 <span class="text-[10px] font-mono text-[var(--muted)] mb-1">03</span> 270 <p class="font-sans font-semibold text-sm">Resolve</p> 271 <p class="text-[11px] text-[var(--muted)] font-sans">IMDB / TMDB</p> 272 </div> 273 <div class="flow-node group flex flex-col items-center text-center px-2"> 274 <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="git-compare" class="w-5 h-5 text-[var(--accent)]"></i></span> 275 <span class="text-[10px] font-mono text-[var(--muted)] mb-1">04</span> 276 <p class="font-sans font-semibold text-sm">Match</p> 277 <p class="text-[11px] text-[var(--muted)] font-sans">Strict scoring</p> 278 </div> 279 <div class="flow-node group flex flex-col items-center text-center px-2"> 280 <span class="fdot fdot-end w-14 h-14 rounded-2xl border border-[var(--accent)] bg-[rgba(255,94,43,0.1)] grid place-items-center mb-3 transition-all duration-300"><i data-lucide="play" class="w-5 h-5 text-[var(--accent)]"></i></span> 281 <span class="text-[10px] font-mono text-[var(--accent)] mb-1">05</span> 282 <p class="font-sans font-semibold text-sm">Play</p> 283 <p class="text-[11px] text-[var(--muted)] font-sans">Stremio / Nuvio</p> 284 </div> 285 </div> 286 </div> 287 </div> 288 289 <!-- Bento grid of capabilities --> 290 <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3"> 291 <!-- Feature hero --> 292 <div class="bento group relative col-span-1 sm:col-span-2 lg:row-span-2 rounded-3xl border border-[var(--line)] p-7 overflow-hidden flex flex-col justify-between min-h-[220px]" data-reveal data-cursor> 293 <div class="flex items-start justify-between">
294 <span class="display text-6xl text-[var(--paper)]/12 group-hover:text-[var(--accent)] transition-colors duration-500">01</span> 295 <i data-lucide="server-cog" class="w-6 h-6 text-[var(--accent)]"></i> 296 </div> 297 <div> 298 <h3 class="display text-3xl mb-2">Serverless by nature</h3> 299 <p class="text-sm text-[var(--paper)]/60 font-sans leading-relaxed max-w-md">Node + TypeScript compiled to a single Vercel function. No always-on server, no database, no ops â it scales to zero and costs nothing at rest.</p> 300 </div> 301 </div> 302 303 <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor> 304 <i data-lucide="database-zap" class="w-5 h-5 text-[var(--accent)] mb-4"></i> 305 <h4 class="font-sans font-semibold text-sm mb-1">Fully stateless</h4> 306 <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Config rides inside the manifest URL. Nothing stored.</p> 307 </div> 308 309 <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor> 310 <i data-lucide="scan-search" class="w-5 h-5 text-[var(--accent)] mb-4"></i> 311 <h4 class="font-sans font-semibold text-sm mb-1">Precise matching</h4> 312 <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Strict scoring returns only the exact title.</p> 313 </div> 314 315 <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor> 316 <i data-lucide="shield-check" class="w-5 h-5 text-[var(--accent)] mb-4"></i> 317 <h4 class="font-sans font-semibold text-sm mb-1">Private by design</h4> 318 <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Credentials never touch a datastore.</p> 319 </div> 320 321 <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor> 322 <i data-lucide="plug" class="w-5 h-5 text-[var(--accent)] mb-4"></i> 323 <h4 class="font-sans font-semibold text-sm mb-1">Protocol-native</h4> 324 <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Stremio v3: catalog, meta & stream.</p> 325 </div> 326 327 <!-- Tech tag strip --> 328 <div class="bento-tags col-span-1 sm:col-span-2 lg:col-span-4 rounded-3xl border border-[var(--line)] p-5 flex flex-wrap items-center gap-2.5" data-reveal> 329 <span class="text-[11px] font-mono uppercase tracking-[0.15em] text-[var(--muted)] mr-2">Built with</span> 330 <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">TypeScript</span> 331 <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">Node · Express</span> 332 <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">Vercel</span> 333 <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">TMDB API</span> 334 <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">Xtream Codes</span> 335 <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">M3U / M3U8</span> 336 <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">LZ-String</span> 337 </div> 338 </div> 339 </div> 340 </section> 341 342 <!-- FAQ --> 343 <section id="faq" class="relative z-10 px-5 sm:px-10 py-28 border-t border-[var(--line)]"> 344 <div class="max-w-[900px] mx-auto"> 345 <h2 class="display text-6xl sm:text-8xl mb-14" data-reveal>Questions</h2> 346 <div class="divide-y divide-[var(--line)]"> 347 <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Do I need a TMDB key?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">It's optional but recommended. A free TMDB v3 key powers poster art, ratings and the IMDB/TMDB resolution that lets global search map any title to your IPTV sources.</p></details> 348 <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Where are my credentials stored?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">Nowhere on a server. They're LZ-compressed into the manifest URL you generate, so the addon is fully stateless and portable.</p></details> 349 <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Does it work in Nuvio as well as Stremio?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">Yes. Both speak the Stremio v3 addon protocol. Use the one-click Stremio install, or paste the manifest URL into Nuvio's add-addon field.</p></details> 350 <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Is hosting really free?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">The whole thing runs as one serverless function that fits comfortably in Vercel's free tier. No database, no always-on server.</p></details> 351 </div> 352 </div> 353 </section> 354 355 <!-- CTA / FOOTER --> 356 <footer class="relative z-10 px-5 sm:px-10 pt-24 pb-10 border-t border-[var(--line)]"> 357 <div class="max-w-[1400px] mx-auto"> 358 <a href="/configure" class="block group" data-cursor> 359 <h2 class="display text-[13vw] leading-[0.9] mb-4 group-hover:text-[var(--accent)] transition-colors">Press play.</h2> 360 </a> 361 362 <!-- Columns --> 363 <div class="grid grid-cols-2 md:grid-cols-4 gap-8 py-14 border-t border-[var(--line)] mt-10"> 364 <div class="col-span-2 md:col-span-1"> 365 <div class="flex items-center gap-2.5 mb-4"> 366 <img src="/logo.svg" class="w-8 h-8 rounded-lg" alt="" />
367 <span class="font-sans font-semibold">IPTV Bridge</span> 368 </div> 369 <p class="text-sm text-[var(--muted)] font-sans leading-relaxed max-w-xs">Turn any Xtream or M3U source into a beautifully organized Stremio & Nuvio experience.</p> 370 </div> 371 <div> 372 <p class="text-xs uppercase tracking-[0.2em] text-[var(--muted)] font-sans mb-4">Product</p> 373 <ul class="space-y-2.5 text-sm font-sans text-[var(--paper)]/70"> 374 <li><a href="#how" class="ul" data-cursor>Method</a></li> 375 <li><a href="#features" class="ul" data-cursor>Features</a></li> 376 <li><a href="#stack" class="ul" data-cursor>Architecture</a></li> 377 <li><a href="/configure" class="ul" data-cursor>Configure your addon</a></li> 378 </ul> 379 </div> 380 <div> 381 <p class="text-xs uppercase tracking-[0.2em] text-[var(--muted)] font-sans mb-4">Resources</p> 382 <ul class="space-y-2.5 text-sm font-sans text-[var(--paper)]/70"> 383 <li><a href="/docs" class="ul" data-cursor>Documentation</a></li> 384 <li><a href="#faq" class="ul" data-cursor>FAQ</a></li> 385 <li><a href="https://www.themoviedb.org/settings/api" target="_blank" class="ul" data-cursor>Get a TMDB key</a></li> 386 <li><a href="https://www.stremio.com" target="_blank" class="ul" data-cursor>Stremio</a></li> 387 <li><a href="https://github.com/jozphe/IPTV-BRIDGE" target="_blank" class="ul" data-cursor>Source on GitHub</a></li> 388 </ul> 389 </div> 390 <div> 391 <p class="text-xs uppercase tracking-[0.2em] text-[var(--muted)] font-sans mb-3">Ready when you are</p> 392 <a href="/configure" class="ember inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-full font-sans font-semibold text-sm leading-none w-full sm:w-auto" data-magnetic data-cursor-big> 393 <span>Configure now</span> <i data-lucide="arrow-up-right" class="w-4 h-4"></i> 394 </a> 395 <p class="text-xs text-[var(--muted)] font-sans mt-3 flex items-center gap-1.5"><i data-lucide="check" class="w-3.5 h-3.5 text-[var(--accent)]"></i> Free · Serverless · Vercel-ready</p> 396 </div> 397 </div> 398 399 <div class="flex flex-wrap items-center justify-between gap-4 pt-8 border-t border-[var(--line)] text-xs text-[var(--muted)] font-sans"> 400 <span>© <span id="year"></span> IPTV Bridge · Built for the Stremio & Nuvio v3 addon protocol.</span> 401 <span>Made for people who just want their stuff to play.</span> 402 </div> 403 </div> 404 </footer> 405 406
406<script src="/theme.js"></script>
406 407
407<script> 408 /* Marquee */ 409 (function(){ 410 const words=['Xtream Codes','M3U','TMDB','IMDB','Live TV','Movies','Series','Global Search','Serverless','Nuvio','Stremio','Vercel']; 411 const seq=words.concat(words); 412 document.getElementById('marquee-track').innerHTML=seq.map(w=>'<span class="flex items-center gap-12"><span class="display text-4xl text-[var(--paper)]/80">'+w+'</span><span class="w-2 h-2 rounded-full bg-[var(--accent)]"></span></span>').join(''); 413 })(); 414 415 /* Reveal + intro animations */ 416 document.addEventListener('DOMContentLoaded', function () { 417 lucide.createIcons(); 418 var y = document.getElementById('year'); if (y) y.textContent = new Date().getFullYear(); 419 420 var hasIO = 'IntersectionObserver' in window; 421 422 // Generic reveals: one-shot CSS transition, no flash, no re-trigger. 423 var revealEls = document.querySelectorAll('[data-reveal]'); 424 if (hasIO) { 425 var io = new IntersectionObserver(function (entries) { 426 entries.forEach(function (entry) { 427 if (entry.isIntersecting) { entry.target.classList.add('shown'); io.unobserve(entry.target); } 428 }); 429 }, { rootMargin: '0px 0px -8% 0px', threshold: 0.12 }); 430 revealEls.forEach(function (el) { io.observe(el); }); 431 } else { 432 revealEls.forEach(function (el) { el.classList.add('shown'); }); 433 } 434 435 // Staggered class-toggle groups (method cards, feature rows). Runs once. 436 function batchReveal(selector, triggerSelector, stagger) { 437 var els = Array.prototype.slice.call(document.querySelectorAll(selector)); 438 if (!els.length) return; 439 var play = function () { els.forEach(function (el, i) { setTimeout(function () { el.classList.add('in'); }, i * stagger); }); }; 440 if (!hasIO) { play(); return; } 441 var trigger = document.querySelector(triggerSelector) || els[0]; 442 var obs = new IntersectionObserver(function (entries) { 443 for (var i = 0; i < entries.length; i++) { 444 if (entries[i].isIntersecting) { play(); obs.disconnect(); break; } 445 } 446 }, { rootMargin: '0px 0px -12% 0px', threshold: 0.1 }); 447 obs.observe(trigger); 448 } 449 batchReveal('.method-card', '#method-grid', 110); 450 batchReveal('.feature-row', '#feature-list', 100); 451 452 // Hero intro timeline only (runs once on load). 453 if (!window.gsap) return; 454 gsap.registerPlugin(ScrollTrigger); 455 ScrollTrigger.config({ limitCallbacks: true, ignoreMobileResize: true }); 456 var tl = gsap.timeline({ defaults: { ease: 'power4.out' } }); 457 gsap.set('[data-hero-line]', { yPercent: 110 }); 458 tl.to('[data-hero-line]', { yPercent: 0, duration: 1.1, stagger: 0.12 }, 0.15) 459 .from('[data-hero-tag]', { opacity: 0, y: 12, stagger: 0.08, duration: 0.6 }, 0.2) 460 .from('[data-hero-sub]', { opacity: 0, y: 20, duration: 0.8 }, 0.6) 461 .from('[data-hero-cta]', { opacity: 0, y: 20, duration: 0.8 }, 0.72) 462 .from('[data-hero-scroll]', { opacity: 0, duration: 0.8 }, 0.9); 463 }); 464 465 </script>
465 466</body> 467</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.