Lansman videosu (Remotion) projesi eklendi

video/ ayrı bir Remotion projesi; Docker imajı, ESLint ve tsc kapsamı dışında.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-10-04 14:00:33 +03:00
parent 9c02b810e7
commit d2359d3f3a
55 changed files with 7492 additions and 1 deletions

View File

@@ -0,0 +1,137 @@
import type {
TransitionPresentation,
TransitionPresentationComponentProps,
} from "@remotion/transitions";
import { AbsoluteFill, Easing, interpolate } from "remotion";
import { H, LOGO_KARELER, PIKSEL, W } from "../marka";
import { clamp01, hash } from "../yardimci";
/**
* Piksel dalgası: yeni sahne, bir noktadan (çoğunlukla imlecin tıkladığı
* yer) yayılan iri piksellerle açılır. Dalganın önünde logonun üç rengi
* (mavi, şeftali, turuncu) yanıp söner — hero haritasındaki ısınan
* piksellerin sahne ölçeğindeki hâli. Hücreler sitenin nokta oranını
* (%74, rx %20) taşır; dalga geçince birleşip kesintisiz yüzeye döner.
*/
export type PikselDalgaProps = {
origin?: { x: number; y: number };
/** Hücre kenarı (px) */
hucre?: number;
/** Dalga önünün kalınlığı (px) */
bant?: number;
/** Dalga önündeki piksellerin renkleri */
renkler?: string[];
/** Çıkan sahne hafifçe geri çekilsin (derinlik) */
geriCekil?: number;
tohum?: number;
};
const VARSAYILAN_RENKLER = LOGO_KARELER.map((k) => k.renk);
const koseUzakligi = (o: { x: number; y: number }) =>
Math.max(
Math.hypot(o.x, o.y),
Math.hypot(W - o.x, o.y),
Math.hypot(o.x, H - o.y),
Math.hypot(W - o.x, H - o.y),
);
/**
* Dalga önünün yarıçapı. Gelen sahne kendi öğelerini dalgayla eş zamanlı
* belirtmek isterse (ör. haritanın noktaları) aynı fonksiyonu kullanır.
*/
export const dalgaYaricapi = (
p: number,
origin: { x: number; y: number } = { x: W / 2, y: H / 2 },
bant = 420,
) =>
interpolate(clamp01(p), [0, 1], [0, koseUzakligi(origin) + bant * 1.25], {
easing: Easing.bezier(0.45, 0.05, 0.4, 1),
});
const PikselDalgaSunum: React.FC<
TransitionPresentationComponentProps<PikselDalgaProps>
> = ({ children, presentationProgress, presentationDirection, passedProps }) => {
const {
origin = { x: W / 2, y: H / 2 },
hucre = 64,
bant = 420,
renkler = VARSAYILAN_RENKLER,
geriCekil = 0.05,
tohum = 3,
} = passedProps;
const p = presentationProgress;
if (presentationDirection === "exiting") {
return (
<AbsoluteFill
style={{
transformOrigin: `${origin.x}px ${origin.y}px`,
scale: `${1 - geriCekil * Easing.in(Easing.cubic)(p)}`,
}}
>
{children}
</AbsoluteFill>
);
}
const sutun = Math.ceil(W / hucre);
const satir = Math.ceil(H / hucre);
const r = dalgaYaricapi(p, origin, bant);
let maske = "";
let renkli = "";
for (let j = 0; j < satir; j++) {
for (let i = 0; i < sutun; i++) {
const cx = i * hucre + hucre / 2;
const cy = j * hucre + hucre / 2;
const d = Math.hypot(cx - origin.x, cy - origin.y) + (hash(i, j, tohum) - 0.5) * bant * 0.55;
const t = clamp01((r - d) / bant);
if (t <= 0) continue;
// Önde renkli piksel belirip söner…
if (t < 0.72) {
const c = Math.sin(Math.PI * (t / 0.72));
const boy = hucre * PIKSEL.nokta * c;
const renk = renkler[Math.floor(hash(i, j, tohum + 9) * renkler.length)];
renkli += `<rect x="${cx - boy / 2}" y="${cy - boy / 2}" width="${boy}" height="${boy}" rx="${boy * PIKSEL.rx}" fill="${renk}"/>`;
}
// …arkasından yeni sahne piksel piksel açılır
const m = Easing.bezier(0.22, 1, 0.36, 1)(clamp01((t - 0.38) / 0.62));
if (m > 0) {
const boy = hucre * (PIKSEL.nokta + 0.3 * m);
const rx = hucre * PIKSEL.rx * (1 - m);
maske += `<rect x="${cx - boy / 2}" y="${cy - boy / 2}" width="${boy}" height="${boy}" rx="${rx}" fill="white"/>`;
}
}
}
const maskeUrl = `url("data:image/svg+xml;utf8,${encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H}" viewBox="0 0 ${W} ${H}">${maske}</svg>`,
)}")`;
return (
<AbsoluteFill>
<AbsoluteFill
style={{
maskImage: maskeUrl,
WebkitMaskImage: maskeUrl,
maskSize: "100% 100%",
WebkitMaskSize: "100% 100%",
maskRepeat: "no-repeat",
WebkitMaskRepeat: "no-repeat",
}}
>
{children}
</AbsoluteFill>
<AbsoluteFill style={{ pointerEvents: "none" }}>
<svg width={W} height={H} dangerouslySetInnerHTML={{ __html: renkli }} />
</AbsoluteFill>
</AbsoluteFill>
);
};
export function pikselDalga(
props: PikselDalgaProps = {},
): TransitionPresentation<PikselDalgaProps> {
return { component: PikselDalgaSunum, props };
}