93 lines
3.7 KiB
TypeScript
93 lines
3.7 KiB
TypeScript
import React from 'react';
|
||
import {random, useCurrentFrame} from 'remotion';
|
||
import {Figur, Kamera} from '../baukasten/figur';
|
||
import {Blende, Vignette} from '../baukasten/helfer';
|
||
import {Blume, Laubhaufen} from '../baukasten/natur';
|
||
import {BODEN, Ort} from '../baukasten/orte';
|
||
import {SCHRIFT, Untertitel} from '../baukasten/untertitel';
|
||
import {TEXTE, plane} from './plan';
|
||
import {HAUFEN_X} from './szene2';
|
||
|
||
// Lied „Einer klein und einer groß“: Refrain (alle), Strophe (Erzählstimme), Refrain.
|
||
// Die drei stehen nebeneinander – klein, mittel, groß – und wippen im Takt.
|
||
|
||
const TAKT = 19; // Frames pro Schlag (ca. 95 bpm)
|
||
|
||
export const LIED = plane(
|
||
'lied',
|
||
[
|
||
{id: 'r1', wer: 'ALLE', dauer: 3.2},
|
||
{id: 'r2', wer: 'ALLE', dauer: 3.2},
|
||
{id: 'r3', wer: 'ALLE', dauer: 3.2},
|
||
{id: 'r4', wer: 'ALLE', dauer: 3.6},
|
||
{id: 's1', wer: 'ERZ', dauer: 3.2},
|
||
{id: 's2', wer: 'ERZ', dauer: 3.2},
|
||
{id: 's3', wer: 'ERZ', dauer: 3.2},
|
||
{id: 's4', wer: 'ERZ', dauer: 3.6},
|
||
{id: 'w1', wer: 'ALLE', dauer: 3.2},
|
||
{id: 'w2', wer: 'ALLE', dauer: 3.2},
|
||
{id: 'w3', wer: 'ALLE', dauer: 3.2},
|
||
{id: 'w4', wer: 'ALLE', dauer: 3.6},
|
||
],
|
||
{vorlauf: 1.0, nachlauf: 1.0},
|
||
);
|
||
|
||
const Note: React.FC<{x: number; y: number; s: number; farbe: string}> = ({x, y, s, farbe}) => (
|
||
<svg width={60} height={80} viewBox="0 0 60 80" style={{position: 'absolute', left: x, top: y, transform: `scale(${s})`}}>
|
||
<ellipse cx={18} cy={64} rx={15} ry={11} fill={farbe} transform="rotate(-20 18 64)" />
|
||
<rect x={30} y={8} width={6} height={58} fill={farbe} />
|
||
<path d="M 36 8 C 50 18, 56 30, 46 44 C 50 30, 44 24, 36 22 Z" fill={farbe} />
|
||
</svg>
|
||
);
|
||
|
||
export const Lied: React.FC = () => {
|
||
const f = useCurrentFrame();
|
||
const {z, dauer} = LIED;
|
||
const schlag = Math.abs(Math.sin((f * Math.PI) / TAKT));
|
||
const wipp = (phase: number, h: number) => -Math.abs(Math.sin((f * Math.PI) / TAKT + phase)) * h;
|
||
const schwank = (phase: number, g: number) => Math.sin((f * Math.PI) / (2 * TAKT) + phase) * g;
|
||
// Strophe: „Lulu holt ihn mit dem Mund“ / „Pino pflückt sie“
|
||
const luluPose: [number, string][] = [
|
||
[0, 'lulu_A3_lachen'],
|
||
[z.s2.start, 'lulu_A_apfel'],
|
||
[z.s3.start, 'lulu_A3_lachen'],
|
||
];
|
||
const pinoPose: [number, string][] = [
|
||
[0, 'pino_A3_lachen'],
|
||
[z.s4.start, 'pino_A_hinterbeine'],
|
||
[z.w1.start, 'pino_A3_lachen'],
|
||
];
|
||
const noaPose: [number, string][] = [
|
||
[0, 'noa_A3_lachen'],
|
||
[z.r4.start, 'noa_A_arme-hoch'],
|
||
[z.s1.start, 'noa_A3_lachen'],
|
||
[z.w4.start, 'noa_A_arme-hoch'],
|
||
];
|
||
return (
|
||
<>
|
||
<Kamera x={1000} y={600} zoom={1.3}>
|
||
<Ort name="garten_herbst" />
|
||
<Laubhaufen x={HAUFEN_X + 380} y={BODEN + 6} />
|
||
<Figur pose={luluPose} x={1300} y={BODEN} drehung={schwank(0.5, 2.2)} stauchY={1 - 0.012 * schlag} blende={8} />
|
||
<Figur pose={noaPose} x={980} y={BODEN + wipp(0.3, 10)} drehung={schwank(0, 3)} blende={8} />
|
||
<Figur pose={pinoPose} x={760} y={BODEN + wipp(0, 16)} drehung={schwank(1, 4)} stauchY={1 - 0.03 * schlag} blende={8} />
|
||
{f >= z.s4.start && f < z.w1.start && <Blume x={764} y={BODEN - 40} s={0.5} />}
|
||
</Kamera>
|
||
{new Array(8).fill(0).map((_, i) => {
|
||
const t = ((f + i * 25) % 200) / 200;
|
||
const x = 200 + random(`n${i}`) * 1500 + Math.sin(t * 6 + i) * 30;
|
||
return (
|
||
<div key={i} style={{opacity: Math.sin(t * Math.PI) * 0.9}}>
|
||
<Note x={x} y={700 - t * 600} s={0.8 + random(`ns${i}`) * 0.6} farbe={['#c8642c', '#3f5a8a', '#5f8a4a', '#a0526b'][i % 4]} />
|
||
</div>
|
||
);
|
||
})}
|
||
<div style={{position: 'absolute', top: 60, left: 0, right: 0, textAlign: 'center', fontFamily: SCHRIFT, fontWeight: 600, fontSize: 40, color: '#8a6a4a', opacity: Math.min(1, f / 20)}}>
|
||
♫ {TEXTE.lied} ♫
|
||
</div>
|
||
<Vignette />
|
||
<Untertitel zeilen={LIED.liste} />
|
||
<Blende dauer={dauer} rein={12} raus={12} />
|
||
</>
|
||
);
|
||
};
|