import React from 'react';
import {AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
import {SCHRIFT, Untertitel} from '../baukasten/untertitel';
import type {Geplant} from '../baukasten/zeit';
import {TEXTE} from './plan';
// Lern-Shorts im Hochformat (1080 × 1920). Die Szene spielt auf der gewohnten Bühne (1920 × 1080,
// Figuren und Orte wie in den Folgen); `Buehne` schneidet daraus den Hochformat-Ausschnitt.
// Frage oben, Untertitel über dem Bereich, den YouTube unten mit Titel und Knöpfen verdeckt.
export const W = 1080;
export const H = 1920;
export const VOLL = H / 1080; // kleinste Vergrößerung, bei der die Bühne das Hochformat füllt
export const Buehne: React.FC<{x: number; y?: number; z?: number; children: React.ReactNode}> = ({x, y = 540, z = VOLL, children}) => {
const halbB = W / 2 / z;
const halbH = H / 2 / z;
// Ist der Ausschnitt größer als die Bühne, bleibt sie mittig (oben/unten Papierrand)
const bx = halbB * 2 >= 1920 ? 960 : Math.min(1920 - halbB, Math.max(halbB, x));
const by = halbH * 2 >= 1080 ? 540 : Math.min(1080 - halbH, Math.max(halbH, y));
return (
{children}
);
};
const KARTE = {
background: 'rgba(255, 250, 240, 0.92)',
borderRadius: 40,
boxShadow: '0 8px 30px rgba(60, 40, 20, 0.22)',
fontFamily: SCHRIFT,
textAlign: 'center',
} as const;
// Frage oben, darunter klein der Kanalname
export const FrageKarte: React.FC<{text: string}> = ({text}) => {
const f = useCurrentFrame();
const {fps} = useVideoConfig();
const s = spring({frame: f - 4, fps, config: {damping: 14}});
return (
{text}
{TEXTE.zeilen.kanal}
);
};
// Untertitel der Folgen, nach oben versetzt (unten liegen im Shorts-Player Titel und Knöpfe);
// das Mitmach-„?“ erscheint unter der Frage-Karte statt darauf
export const HochUntertitel: React.FC<{zeilen: Geplant[]}> = ({zeilen}) => (
);
// Runde Bildkarte, die bei `ab` aufploppt (Bildschirm-Koordinaten des Hochformats)
export const BildKarte: React.FC<{x: number; y: number; ab: number; r?: number; aus?: number; children: React.ReactNode}> = ({x, y, ab, r = 150, aus = 1e9, children}) => {
const f = useCurrentFrame();
const {fps} = useVideoConfig();
const s = spring({frame: f - ab, fps, config: {damping: 11}});
const weg = interpolate(f, [aus, aus + 10], [1, 0], {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'});
if (f < ab) return null;
return (
{children}
);
};
// Großes Wort zum Mitsagen (klein – mittel – groß)
// `puls`: Zeitpunkte, an denen das Wort noch einmal kurz groß wird (beim Mitsagen)
export const Wort: React.FC<{text: string; x: number; y: number; ab: number; puls?: number[]; groesse?: number; farbe?: string}> = ({text, x, y, ab, puls = [], groesse = 90, farbe = '#c8502c'}) => {
const f = useCurrentFrame();
const {fps} = useVideoConfig();
if (f < ab) return null;
const pulsen = puls.reduce((m, p) => m + 0.35 * Math.max(0, Math.sin(Math.PI * Math.min(1, Math.max(0, (f - p) / 18)))), 0);
const s = spring({frame: f - ab, fps, config: {damping: 10}}) + pulsen;
return (
{text}
);
};
// `hintergrund`: füllt oben und unten, wenn die Bühne das Hochformat nicht ganz ausfüllt
export const Hochformat: React.FC<{hintergrund?: string; children: React.ReactNode}> = ({hintergrund = '#f4ead8', children}) => (
{children}
);