import type { ReactNode } from "react"; import { AbsoluteFill, Easing, useCurrentFrame } from "remotion"; import { YagmurHaritasi } from "./harita"; import { Ikon, type IkonAdi } from "./ikonlar"; import { LogoMark } from "./logo"; import { BaslikBlogu, Kutu, RiskEtiketi, Sahne, TuruncuCta, useDuzen } from "./ortak"; import { Eyebrow, PixelCorner, Wordmark } from "./piksel"; import { Kamera, MaskeSatir, OdakDisiPikseller, degerAl, type Anahtar } from "./sinema"; import { Telefon } from "./telefon"; import { FONT, R, ara, trSayi, yay, zipla } from "./tema"; import { VURUSLAR } from "./vurus"; const vurguStil = { fontFamily: FONT.vurgu, fontStyle: "italic" as const, fontWeight: 800, letterSpacing: "-0.04em", color: R.primary, }; /* ------------------------------------------------------------------ */ /* Adım 1 — 3B telefonda sihirbaz: sıralama, çipler, CTA */ /* ------------------------------------------------------------------ */ const CIPLER = ["Mühendislik", "Bilgisayar", "İstanbul", "Ankara", "İzmir", "Devlet"]; // Seçim kareleri imleç tıklarıyla aynı (zaman.json) const SECIM: Record = { 0: 58, 1: 66, 2: 74, 3: 82, 5: 92 }; function SihirbazEkrani() { const frame = useCurrentFrame(); const metin = "45.320"; const yazilan = metin.slice(0, Math.max(0, Math.floor((frame - 22) / 4))); const odak = frame >= 20; const imlecGorunur = Math.floor(frame / 8) % 2 === 0 || yazilan.length < metin.length; const cta = zipla(frame, 96); const bas = ara(frame, [122, 125], [0, 1]) * (1 - ara(frame, [129, 134], [0, 1])); const sayfa = yay(frame, 128, 22); return (
{/* Site üst çubuğu */}
Adım 1 / 3
Sıralamanı gir
Sana uyan programları bununla bulacağız.
Başarı sıralaman
{yazilan} {odak && imlecGorunur ? | : null} {!yazilan && !odak ? Örn. 45.320 : null}
Neyi seviyorsun, nerede okumak istersin?
{CIPLER.map((c, i) => { const an = SECIM[i]; const secili = an != null && frame >= an; const tik = an != null ? ara(frame, [an, an + 2], [0, 1]) * (1 - ara(frame, [an + 3, an + 7], [0, 1])) : 0; return ( {i >= 2 && i <= 4 ? : i === 5 ? : null} {c} ); })}
{/* CTA'dan sonra: liste hazırlanıyor paneli (3. adıma köprü) */}
Listen hazırlanıyor
6 yılın verisi taranıyor…
{Array.from({ length: 24 }, (_, i) => { const on = frame >= 134 + i * 1.2; const renk = i < 5 ? R.riskli : i < 18 ? R.azRiskli : R.guvenli; return ; })}
); } export function Adim1() { const frame = useCurrentFrame(); const { dikey, w, h } = useDuzen(); const telGen = dikey ? 640 : 470; const telDon = [ { f: 0, s: -28, x: 12, r: -3 }, { f: 34, s: -10, x: 5, r: -1 }, { f: 70, s: 0, x: 0, r: 0 }, { f: 185, s: 9, x: 4, r: 1 }, ].map((a) => ({ f: a.f, s: a.s, x: a.x, r: a.r })); const donY = degerAl(telDon as Anahtar[], frame, "s", 0); const donX = degerAl(telDon as Anahtar[], frame, "x", 0); const donZ = degerAl(telDon as Anahtar[], frame, "r", 0); const kamera: Anahtar[] = dikey ? [ { f: 0, s: 0.95, x: 0, y: 60 }, { f: 24, s: 1.4, x: 0, y: -40 }, { f: 50, s: 1.4, x: 0, y: -40 }, { f: 64, s: 1.3, x: 0, y: 140 }, { f: 100, s: 1.3, x: 0, y: 150 }, { f: 118, s: 1.42, x: 0, y: 290 }, { f: 140, s: 1.3, x: 0, y: 420 }, { f: 185, s: 1, x: 0, y: 60 }, ] : [ { f: 0, s: 1, x: 0, y: 0 }, { f: 24, s: 1.6, x: 384, y: -140 }, { f: 50, s: 1.6, x: 384, y: -140 }, { f: 64, s: 1.55, x: 384, y: -10 }, { f: 100, s: 1.55, x: 384, y: 0 }, { f: 118, s: 1.7, x: 384, y: 90 }, { f: 140, s: 1.5, x: 384, y: 250 }, { f: 185, s: 1, x: 0, y: 0 }, ]; return (
{!dikey ? ( Adım 1 ) : null}
Form doldurmaktan kısa sürer.
{!dikey ? ( Sıralamanı yaz, sevdiğin alanları ve şehirleri seç. Gerisini bir butona bırak. ) : null}
); } /* ------------------------------------------------------------------ */ /* Adım 2 — hero haritası dökülür, imleç ısı fırçasıyla tarar */ /* ------------------------------------------------------------------ */ const ISTATISTIK = [ { deger: "21.000+", etiket: "Taranan program" }, { deger: "6 yıl", etiket: "Taban sıralaması trendi" }, { deger: "%100", etiket: "Resmî YÖK Atlas kaynağı" }, ]; export function Adim2() { const frame = useCurrentFrame(); const { dikey } = useDuzen(); const kilit = yay(frame, 150, 20); const haritaY = dikey ? -70 : -40; const kamera: Anahtar[] = [ { f: 0, s: 1.42, x: 0, y: haritaY }, { f: 58, s: 1.3, x: 0, y: haritaY }, { f: 118, s: 1.22, x: 0, y: haritaY }, { f: 138, s: 1, x: 0, y: 0 }, { f: 200, s: 1.04, x: 0, y: 0 }, ]; return (
{ISTATISTIK.map((s, i) => { const g = yay(frame, 124 + i * 8, 20); return (
{s.deger}
{s.etiket}
); })}
Yapay zekâ bu havuzun dışına çıkamaz. Uydurmak yok.
); } /* ------------------------------------------------------------------ */ /* Adım 3 — 24 kare dolar, imleç her yeni kareyi takip eder */ /* ------------------------------------------------------------------ */ const DILIMLER = [ { ad: "Hayal", adet: 5, renk: R.riskli }, { ad: "Dengeli", adet: 13, renk: R.azRiskli }, { ad: "Güvenli", adet: 6, renk: R.guvenli }, ] as const; const KARELER = DILIMLER.flatMap((d) => Array.from({ length: d.adet }, () => d)); // Gerçek YÖK Atlas 2026 taban sıralamaları (data/yokatlas.db, SAYISAL); // örnek aday 45.320. — risk riskHesapla() eşikleriyle birebir. const SATIRLAR = [ { sira: 3, ad: "Elektrik-Elektronik Mühendisliği", uni: "Dokuz Eylül Üniversitesi", il: "İzmir", taban: 38626, risk: "riskli" as const }, { sira: 11, ad: "Bilgisayar Mühendisliği", uni: "Ankara Yıldırım Beyazıt Üniversitesi", il: "Ankara", taban: 55158, risk: "az-riskli" as const }, { sira: 20, ad: "Bilgisayar Mühendisliği", uni: "Kocaeli Üniversitesi", il: "Kocaeli", taban: 70832, risk: "guvenli" as const }, ]; export function Adim3() { const frame = useCurrentFrame(); const { dikey } = useDuzen(); const kare = dikey ? 112 : 92; const arali = dikey ? 16 : 12; const sut = dikey ? 6 : 8; const BAS = 24; // İmlecin takip ettiği nokta: dolmakta olan kare const t = Math.min(23, Math.max(0, (frame - BAS) / 2)); const kareMerkez = (i: number) => [(i % sut) * (kare + arali) + kare / 2, Math.floor(i / sut) * (kare + arali) + kare / 2]; const a = kareMerkez(Math.floor(t)); const b = kareMerkez(Math.min(23, Math.floor(t) + 1)); const f = t - Math.floor(t); const takip = [a[0] + (b[0] - a[0]) * f, a[1] + (b[1] - a[1]) * f]; const kamera: Anahtar[] = dikey ? [ { f: 0, s: 1.16, x: 0, y: -190 }, { f: 80, s: 1.1, x: 0, y: -160 }, { f: 112, s: 1.15, x: 0, y: 500 }, { f: 150, s: 1.1, x: 0, y: 520 }, { f: 185, s: 1, x: 0, y: 0 }, ] : [ { f: 0, s: 1.45, x: -435, y: 90 }, { f: 80, s: 1.3, x: -420, y: 110 }, { f: 112, s: 1.45, x: 455, y: 120 }, { f: 150, s: 1.35, x: 455, y: 130 }, { f: 185, s: 1, x: 0, y: 0 }, ]; const izgara = (
{KARELER.map((d, i) => { const s = zipla(frame, BAS + i * 2); return (
{i + 1}
); })}
{DILIMLER.map((d, i) => { const g = yay(frame, 78 + i * 6, 16); return ( {d.ad} {d.adet} ); })}
); const satirlar = (
{SATIRLAR.map((s, i) => { const g = yay(frame, 96 + i * 9, 20); const hover = (i === 1 && frame >= 100 && frame < 132) || (i === 2 && frame >= 130 && frame < 158); return (
{s.sira}
{s.ad}
{s.uni} · {s.il}
Taban {trSayi(s.taban)}
); })}
Örnek: sayısal, 45.320. sıra · YÖK Atlas 2026 taban sıralamaları
); return (
{izgara} {satirlar}
); } /* ------------------------------------------------------------------ */ /* Paket içinde — trend, PDF, revizyon (satır imleçle sürüklenir) */ /* ------------------------------------------------------------------ */ // Ankara Yıldırım Beyazıt Ü. Bilgisayar Müh. taban sırası, 2021–2026 const TREND = [37831, 27534, 21602, 30797, 42108, 55158]; const REVIZYON = [ { ad: "Bilgisayar Müh. · Ege", renk: R.riskli }, { ad: "Bilgisayar Müh. · Dokuz Eylül", renk: R.azRiskli }, { ad: "Bilgisayar Müh. · Katip Çelebi", renk: R.guvenli }, ]; function OzellikKarti({ ikon, baslik, aciklama, gecikme, children, dikey, }: { ikon: IkonAdi; baslik: string; aciklama: string; gecikme: number; children: ReactNode; dikey: boolean; }) { const frame = useCurrentFrame(); const g = yay(frame, gecikme, 22); return (
{baslik}
{aciklama}
{children}
); } export function Ozellikler() { const frame = useCurrentFrame(); const { dikey } = useDuzen(); const gW = dikey ? 380 : 420; const gH = dikey ? 200 : 170; const min = 15000; const max = 60000; const noktalar = TREND.map((v, i) => [(i / (TREND.length - 1)) * gW, ((v - min) / (max - min)) * gH]); const cizgi = ara(frame, [26, 58], [0, 1]); const yol = noktalar.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join(" "); // Sürükle-bırak: imleç 58'de ilk satırı tutar, 92'de en alta bırakır const tut = ara(frame, [58, 92], [0, 1], Easing.inOut(Easing.cubic)); const tutuldu = frame >= 58 && frame < 94; const SATIR = 74; return (
Paket içinde
Her tercihin bir “neden”i var.
{noktalar.map((p, i) => ( = i / (TREND.length - 1) ? 1 : 0} /> ))}
{[2, 1, 0].map((k) => { const s = yay(frame, 34 + (2 - k) * 6, 18); return (
{k === 0 ? ( <>
{[R.riskli, R.azRiskli, R.guvenli].map((c) => ( ))}
{[1, 0.8, 0.9, 0.6, 0.75].map((wd, j) => ( ))} ) : null}
); })}
{REVIZYON.map((r, i) => { // 0. satır sürüklenir; diğerleri yukarı kayarak yer açar // Sürüklenen satır i'nin üstünden geçince o satır bir basamak yukarı kayar const gecis = i === 1 ? (2 * tut - 0.5) / 0.8 : (2 * tut - 1.3) / 0.7; const kay = Easing.inOut(Easing.cubic)(Math.min(1, Math.max(0, gecis))); const y = i === 0 ? tut * 2 * SATIR : (i - kay) * SATIR; const kalkis = i === 0 && tutuldu ? 1 : 0; return (
{r.ad} {i === 0 ? ( {Array.from({ length: 6 }, (_, k) => ( ))} ) : null}
); })}
); } /* ------------------------------------------------------------------ */ /* Dürüstlük notu */ /* ------------------------------------------------------------------ */ export function Durustluk() { const frame = useCurrentFrame(); const { dikey } = useDuzen(); const kalkan = zipla(frame, 0); const alt = yay(frame, 64, 18); return (
Yerleşme garantisi vermiyoruz.
Çünkü kimse veremez.
Veren olursa, uzak dur. Biz riski satır satır gösteririz.
{(["guvenli", "az-riskli", "riskli"] as const).map((r, i) => ( ))}
); } /* ------------------------------------------------------------------ */ /* Kapanış — yalnız logo, tipografi, buton. Tıkla → her şey imlecin */ /* içine çöker → ilk kare: döngü */ /* ------------------------------------------------------------------ */ export function Kapanis() { const frame = useCurrentFrame(); const { dikey } = useDuzen(); const buton = zipla(frame, 40); const bas = ara(frame, [118, 121], [0, 1]) * (1 - ara(frame, [125, 130], [0, 1])); // Çöküş: tıktan sonra içerik butonun olduğu noktaya büzülür const cok = ara(frame, [124, 150], [0, 1], Easing.bezier(0.7, 0, 0.84, 0)); return (
Listeni kur, panikle değil.
); }