feat: KolayTercih lansman videosu (Remotion, v3)
64 saniyelik, kesintisiz döngü lansman filmi; 9:16 ve 16:9. - remocn.dev bileşenleri (sheen-slide-in, tracking-in, gradient-scale-cut-text, outline-fill-track-text, perspective-marquee, path-ride, zoom-blur, lens-zoom) KolayTercih piksel diline uyarlandı (src/kinetik.tsx) - Sahne içi imleç + imleci takip eden kamera, piksel iz ve tık patlaması - Sessizlik → BAM kurgusu (lensZoom), punch zoom ve hareket bulanıklığı - Müzik ve efektler numpy ile sentezlendi (ses/uret.py), zaman.json tek kaynak - Örnek taban sıralamaları gerçek YÖK Atlas 2026 kayıtları Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
252
src/sahneler-1.tsx
Normal file
252
src/sahneler-1.tsx
Normal file
@@ -0,0 +1,252 @@
|
||||
import { measureText } from "@remotion/layout-utils";
|
||||
import { AbsoluteFill, Easing, interpolate, useCurrentFrame } from "remotion";
|
||||
import { IzAc, PikselDevKesme, PikselMarquee, PikselSheen } from "./kinetik";
|
||||
import { LogoMark } from "./logo";
|
||||
import { Sahne, useDuzen } from "./ortak";
|
||||
import { Eyebrow, KelimeKelime, Wordmark } from "./piksel";
|
||||
import { Kamera, MaskeSatir, OdakDisiPikseller } from "./sinema";
|
||||
import { FONT, R, ara, hash, trSayi, zipla } from "./tema";
|
||||
import { VURUSLAR } from "./vurus";
|
||||
|
||||
export const vurguStil = {
|
||||
fontFamily: FONT.vurgu,
|
||||
fontStyle: "italic" as const,
|
||||
fontWeight: 800,
|
||||
letterSpacing: "-0.04em",
|
||||
color: R.primary,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Açılış — boş ekran → "45.320." (Track Text) → tebrik */
|
||||
/* ------------------------------------------------------------------ */
|
||||
export function Acilis() {
|
||||
const { dikey } = useDuzen();
|
||||
return (
|
||||
<Sahne>
|
||||
<Kamera anahtarlar={[{ f: 0, s: 1.08 }, { f: 110, s: 1 }]} vuruslar={VURUSLAR.acilis}>
|
||||
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center", gap: 44, textAlign: "center" }}>
|
||||
<MaskeSatir gecikme={8} sure={18}>
|
||||
<Eyebrow olcek={dikey ? 2.8 : 2.4}>YKS sonuçları açıklandı</Eyebrow>
|
||||
</MaskeSatir>
|
||||
<IzAc gecikme={14} fontSize={dikey ? 250 : 240}>
|
||||
45.320<span style={{ color: R.primary }}>.</span>
|
||||
</IzAc>
|
||||
<div style={{ fontFamily: FONT.baslik, fontWeight: 700, fontSize: dikey ? 88 : 84, lineHeight: 1.1, maxWidth: dikey ? 960 : 1600 }}>
|
||||
<MaskeSatir gecikme={42}>Sıralaman geldi. Tebrikler!</MaskeSatir>
|
||||
<MaskeSatir gecikme={56} style={{ color: R.slate500 }}>
|
||||
Sırada küçük bir <span style={vurguStil}>bulmaca</span> var.
|
||||
</MaskeSatir>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
</Kamera>
|
||||
</Sahne>
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Seçenekler — Perspective Marquee: akıp giden bölümler, 21.000+ / 24 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
const UST_SIRA = ["Bilgisayar Mühendisliği", "Hukuk", "Tıp", "Psikoloji", "Mimarlık", "İşletme", "Hemşirelik"];
|
||||
const ALT_SIRA = ["Diş Hekimliği", "Endüstri Mühendisliği", "Öğretmenlik", "Uluslararası İlişkiler", "Yazılım Mühendisliği", "Eczacılık"];
|
||||
|
||||
export function Secenek() {
|
||||
const frame = useCurrentFrame();
|
||||
const { dikey, h } = useDuzen();
|
||||
const sayi = ara(frame, [4, 40], [0, 21000], Easing.bezier(0.16, 1, 0.3, 1));
|
||||
const arti = zipla(frame, 38);
|
||||
return (
|
||||
<Sahne>
|
||||
<Kamera anahtarlar={[{ f: 0, s: 1.02 }, { f: 125, s: 1.12 }]} vuruslar={VURUSLAR.secenek}>
|
||||
<div style={{ position: "absolute", left: 0, right: 0, top: h * (dikey ? 0.2 : 0.14) - 60 }}>
|
||||
<PikselMarquee ogeler={UST_SIRA} fontSize={dikey ? 100 : 96} hiz={6} renk={R.slate400} donY={-22} donX={10} />
|
||||
</div>
|
||||
<div style={{ position: "absolute", left: 0, right: 0, top: h * (dikey ? 0.8 : 0.86) - 60 }}>
|
||||
<PikselMarquee ogeler={ALT_SIRA} fontSize={dikey ? 100 : 96} hiz={5} renk={R.slate400} donY={22} donX={-10} ters />
|
||||
</div>
|
||||
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center", textAlign: "center" }}>
|
||||
<div style={{ fontFamily: FONT.baslik, fontWeight: 700, fontSize: dikey ? 230 : 240, lineHeight: 1, color: R.slate900, letterSpacing: "-0.01em" }}>
|
||||
{trSayi(sayi)}
|
||||
<span style={{ display: "inline-block", color: R.primary, transform: `scale(${Math.max(0, arti)})` }}>+</span>
|
||||
</div>
|
||||
<div style={{ marginTop: 16, fontSize: dikey ? 46 : 42, fontWeight: 600, color: R.slate500 }}>program var.</div>
|
||||
<div style={{ marginTop: dikey ? 70 : 50 }}>
|
||||
<PikselSheen gecikme={50} fontSize={dikey ? 86 : 88}>
|
||||
Senin <span style={{ color: R.primary }}>24</span> hakkın var.
|
||||
</PikselSheen>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
</Kamera>
|
||||
</Sahne>
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Kaos — sekmeler gibi açılan sorular, sonra ani sessizlik */
|
||||
/* ------------------------------------------------------------------ */
|
||||
const SORULAR = [
|
||||
"Geçen yılın tabanı yeter mi?",
|
||||
"Kontenjan düştü mü?",
|
||||
"Hangi şehir?",
|
||||
"Devlet mi, vakıf mı?",
|
||||
"Danışman 3.000 TL mi?!",
|
||||
"Teyzem “hukuk yaz” dedi",
|
||||
"Ya boşta kalırsam?",
|
||||
"Hangisi kaçıncı sıraya?",
|
||||
];
|
||||
const YER_YATAY = [
|
||||
[-0.62, -0.62], [0.55, -0.7], [-0.78, -0.08], [0.74, -0.18],
|
||||
[-0.6, 0.55], [0.58, 0.52], [-0.12, 0.8], [0.1, -0.86],
|
||||
];
|
||||
const YER_DIKEY = [
|
||||
[-0.38, -0.74], [0.36, -0.6], [-0.42, -0.42], [0.4, -0.3],
|
||||
[-0.36, 0.34], [0.38, 0.48], [-0.3, 0.66], [0.32, 0.8],
|
||||
];
|
||||
|
||||
export function Kaos() {
|
||||
const frame = useCurrentFrame();
|
||||
const { dikey, w, h } = useDuzen();
|
||||
const yerler = dikey ? YER_DIKEY : YER_YATAY;
|
||||
// Sonda kartlar hızlanır, ekran doluyor hissi; sonra sessizliğe sert kesme
|
||||
const telas = ara(frame, [60, 104], [0, 1], Easing.in(Easing.quad));
|
||||
return (
|
||||
<Sahne>
|
||||
<Kamera anahtarlar={[{ f: 0, s: 0.96, r: -1.2 }, { f: 104, s: 1.14, r: 0.8 }]} vuruslar={VURUSLAR.kaos}>
|
||||
{SORULAR.map((s, i) => {
|
||||
const [nx, ny] = yerler[i];
|
||||
const g = zipla(frame, 6 + i * 5);
|
||||
const hizli = 1 + telas * 3;
|
||||
const yuzX = Math.sin(((frame + i * 20) / 18) * hizli) * (16 + telas * 20);
|
||||
const yuzY = Math.cos(((frame + i * 13) / 15) * hizli) * (14 + telas * 18);
|
||||
// Sırayla "sekme değiştirme" vurgusu
|
||||
const aktif = Math.floor(frame / 9) % SORULAR.length === i && frame > 20;
|
||||
return (
|
||||
<div
|
||||
key={s}
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: w / 2 + nx * (w / 2) + yuzX,
|
||||
top: h / 2 + ny * (h / 2) + yuzY,
|
||||
transform: `translate(-50%, -50%) scale(${Math.max(0, g) * (aktif ? 1.07 : 1)}) rotate(${(hash(i, 1, 2) - 0.5) * 10}deg)`,
|
||||
background: aktif ? "#fff7ed" : R.beyaz,
|
||||
border: `3px solid ${aktif ? R.turuncu : R.slate200}`,
|
||||
borderRadius: 30,
|
||||
padding: dikey ? "24px 32px" : "22px 30px",
|
||||
fontSize: dikey ? 38 : 34,
|
||||
fontWeight: 600,
|
||||
color: aktif ? R.turuncu : R.slate700,
|
||||
whiteSpace: "nowrap",
|
||||
boxShadow: "0 12px 30px rgba(15,23,42,0.08)",
|
||||
}}
|
||||
>
|
||||
{s}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
|
||||
<h2
|
||||
style={{
|
||||
margin: 0,
|
||||
textAlign: "center",
|
||||
fontFamily: FONT.baslik,
|
||||
fontWeight: 700,
|
||||
fontSize: 104,
|
||||
lineHeight: 1.08,
|
||||
maxWidth: dikey ? 800 : 1200,
|
||||
background: `radial-gradient(closest-side, ${R.slate50} 60%, rgba(248,250,252,0))`,
|
||||
padding: "40px 60px",
|
||||
}}
|
||||
>
|
||||
<KelimeKelime metin="Kafanda yüz sekme açık, değil mi?" gecikme={4} aralik={3} vurgu={["yüz", "sekme"]} />
|
||||
</h2>
|
||||
</AbsoluteFill>
|
||||
</Kamera>
|
||||
</Sahne>
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Nefes — sessizlik. Tek bir turuncu piksel nefes alır. */
|
||||
/* ------------------------------------------------------------------ */
|
||||
export function Nefes() {
|
||||
const frame = useCurrentFrame();
|
||||
const { dikey } = useDuzen();
|
||||
const nefes = 1 + 0.12 * Math.sin((frame / 30) * Math.PI * 1.1);
|
||||
const kare = dikey ? 64 : 56;
|
||||
return (
|
||||
<Sahne zemin={R.beyaz}>
|
||||
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center", gap: 56 }}>
|
||||
<div
|
||||
style={{
|
||||
width: kare,
|
||||
height: kare,
|
||||
borderRadius: kare * 0.23,
|
||||
background: R.logoTuruncu,
|
||||
opacity: interpolate(frame, [2, 12], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }),
|
||||
transform: `scale(${nefes})`,
|
||||
}}
|
||||
/>
|
||||
<div style={{ fontFamily: FONT.baslik, fontWeight: 700, fontSize: dikey ? 64 : 60, color: R.slate400 }}>
|
||||
<MaskeSatir gecikme={10} sure={24}>
|
||||
Derin bir nefes al.
|
||||
</MaskeSatir>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
</Sahne>
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Logo — BAM: dev piksel kelime süpürür, logoya kesilir, slogan sheen */
|
||||
/* ------------------------------------------------------------------ */
|
||||
export function LogoSahnesi() {
|
||||
const frame = useCurrentFrame();
|
||||
const { dikey } = useDuzen();
|
||||
const markBoy = dikey ? 250 : 230;
|
||||
const yaziBoy = dikey ? 130 : 150;
|
||||
// Kilit: işaret + yazı (yatayda yan yana, dikeyde alt alta)
|
||||
const yaziGen =
|
||||
measureText({ text: "Kolay", fontFamily: "Bricolage", fontSize: yaziBoy, fontWeight: "300", letterSpacing: `${-0.05 * yaziBoy}px` }).width +
|
||||
measureText({ text: "Tercih", fontFamily: "Bricolage", fontSize: yaziBoy, fontWeight: "600", letterSpacing: `${-0.05 * yaziBoy}px` }).width;
|
||||
const kilit = (
|
||||
<div style={{ display: "flex", flexDirection: dikey ? "column" : "row", alignItems: "center", gap: dikey ? 10 : 24, transform: `translateY(${dikey ? -170 : -120}px)` }}>
|
||||
<LogoMark boy={markBoy} girisYok rotaBas={32} />
|
||||
<div style={{ width: dikey ? undefined : yaziGen }}>
|
||||
<Wordmark boy={yaziBoy} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Sahne zemin={R.beyaz}>
|
||||
<OdakDisiPikseller seed={3} adet={8} guc={ara(frame, [30, 60], [0, 1])} />
|
||||
<Kamera anahtarlar={[{ f: 0, s: 1.1 }, { f: 130, s: 1 }]} vuruslar={VURUSLAR.logo}>
|
||||
<PikselDevKesme metin="KolayTercih" devBoy={dikey ? 420 : 520} gecikme={8} kesme={18}>
|
||||
{kilit}
|
||||
</PikselDevKesme>
|
||||
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center", textAlign: "center" }}>
|
||||
<div style={{ marginTop: dikey ? 560 : 400, display: "flex", flexDirection: "column", alignItems: "center", gap: 6 }}>
|
||||
{dikey ? (
|
||||
<>
|
||||
<PikselSheen gecikme={46} fontSize={76}>
|
||||
Tercih listeni
|
||||
</PikselSheen>
|
||||
<PikselSheen gecikme={52} fontSize={76}>
|
||||
gerçek veriyle kur,
|
||||
</PikselSheen>
|
||||
</>
|
||||
) : (
|
||||
<PikselSheen gecikme={46} fontSize={80}>
|
||||
Tercih listeni gerçek veriyle kur,
|
||||
</PikselSheen>
|
||||
)}
|
||||
<div style={{ fontSize: dikey ? 76 : 80, lineHeight: 1.1 }}>
|
||||
<MaskeSatir gecikme={62}>
|
||||
<span style={vurguStil}>panikle</span>
|
||||
<span style={{ fontFamily: FONT.baslik, fontWeight: 700, color: R.slate900 }}> değil.</span>
|
||||
</MaskeSatir>
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
</Kamera>
|
||||
</Sahne>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user