Liedvideo Lied 4 „Wer hat den längsten Hals?“ (DE/ES/FR); Vorlage: kräftigere Leuchtkreise, Satzzeichen im Mitlesetext

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lara 2026-11-08 19:36:19 +00:00
parent a4809d4089
commit 6489b61dc3
5 changed files with 264 additions and 33 deletions

View file

@ -24,6 +24,7 @@ import {SZENEN as SZENEN_F08} from './folge08/Folge08';
import {LIED01_DAUER, Lied01} from './lieder/lied01/Lied01';
import {LIED02_DAUER, Lied02} from './lieder/lied02/Lied02';
import {LIED03_DAUER, Lied03} from './lieder/lied03/Lied03';
import {LIED04_DAUER, Lied04} from './lieder/lied04/Lied04';
const BILD = {fps: 30, width: 1920, height: 1080} as const;
@ -31,6 +32,7 @@ export const Root: React.FC = () => (
<>
<Composition id="Lied01" component={Lied01} durationInFrames={LIED01_DAUER} {...BILD} />
<Composition id="Lied02" component={Lied02} durationInFrames={LIED02_DAUER} {...BILD} />
<Composition id="Lied04" component={Lied04} durationInFrames={LIED04_DAUER} {...BILD} />
<Composition id="Lied03" component={Lied03} durationInFrames={LIED03_DAUER} {...BILD} />
<Composition id="GangTest" component={GangTest} durationInFrames={GANGTEST_DAUER} {...BILD} />
<Composition id="LaterneTest" component={LaterneTest} durationInFrames={420} {...BILD} />

View file

@ -38,8 +38,9 @@ const WEIT = {x: 1030, y: 640, z: 1.2};
export const wortZeit = (z: Zeile, wort: number) => zerlege(z.zeile)[wort]?.t ?? z.start;
// Weicher Leuchtkreis: blendet ein, atmet ganz langsam (kein Blinken)
const Leuchtkreis: React.FC<Punkt & {farbe: string; r?: number; ab: number; bis: number}> = ({x, y, farbe, r = 70, ab, bis}) => {
const Leuchtkreis: React.FC<Punkt & {farbe: string; r?: number; ab: number; bis: number}> = ({x, y, farbe, r = 70, ab, bis: bisRoh}) => {
const f = useCurrentFrame();
const bis = Math.max(bisRoh, ab + 20); // spätes Wort am Zeilenende: trotzdem kurz sichtbar
const an = interpolate(f, [ab, ab + 10, bis - 8, bis], [0, 1, 1, 0], {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'});
if (an <= 0) return null;
const atem = 0.85 + 0.15 * Math.sin(f * 0.06);
@ -52,8 +53,9 @@ const Leuchtkreis: React.FC<Punkt & {farbe: string; r?: number; ab: number; bis:
width: 2 * r,
height: 2 * r,
borderRadius: '50%',
background: `radial-gradient(closest-side, ${farbe}88, ${farbe}44 55%, ${farbe}00)`,
border: `5px solid ${farbe}`,
background: `radial-gradient(closest-side, ${farbe}aa, ${farbe}55 55%, ${farbe}00)`,
border: `6px solid ${farbe}`,
boxShadow: '0 0 0 4px rgba(255,250,240,0.85)',
opacity: an * atem,
transform: `scale(${0.9 + 0.1 * an})`,
}}

View file

@ -10,7 +10,7 @@ export const DE: {dauer: number; zeilen: Zeile[]} = {
{abschnitt: "Chorus", zeile: "Zeig,@10.27 zeig,@11.03 zeig@11.59 mal@11.87 hin!@12.11", start: 10.27},
{abschnitt: "Chorus", zeile: "Such@12.87 die@13.03 Farben,@13.33 schau@14.11 gut@14.31 hin!@14.61", start: 12.87},
{abschnitt: "Chorus", zeile: "Rot@15.23 und@15.53 Gelb@15.81 und@16.25 Blau@16.41 und@16.85 Grün,@17.03", start: 15.23},
{abschnitt: "Chorus", zeile: "alle@17.77 Farben_\u0001@18.05 das@19.01 ist@19.17 schön!@19.41", start: 17.77},
{abschnitt: "Chorus", zeile: "alle@17.77 Farben_–@18.05 das@19.01 ist@19.17 schön!@19.41", start: 17.77},
{abschnitt: "Verse 1", zeile: "Wer@20.91 trägt@21.63 Rot?@21.95 Wer@22.61 trägt@22.81 Rot?@23.17", start: 20.91},
{abschnitt: "Verse 1", zeile: "Rot@23.85 wie@24.71 Noas@24.97 Stiefel!@25.45", start: 23.85},
{abschnitt: "Verse 1", zeile: "Rot@26.59 wie@27.27 Noas@27.93 Stiefel!@29.01", start: 26.59},
@ -20,7 +20,7 @@ export const DE: {dauer: number; zeilen: Zeile[]} = {
{abschnitt: "Chorus", zeile: "Zeig,@41.49 zeig,@42.23 zeig@42.83 mal@43.07 hin!@43.31", start: 41.49},
{abschnitt: "Chorus", zeile: "Such@44.09 die@44.25 Farben,@44.51 schau@45.33 gut@45.53 hin!@45.83", start: 44.09},
{abschnitt: "Chorus", zeile: "Rot@46.45 und@46.77 Gelb@47.01 und@47.45 Blau@47.61 und@48.05 Grün,@48.23", start: 46.45},
{abschnitt: "Chorus", zeile: "alle@48.99 Farben_\u0001@49.25 das@50.21 ist@50.33 schön!@50.61", start: 48.99},
{abschnitt: "Chorus", zeile: "alle@48.99 Farben_–@49.25 das@50.21 ist@50.33 schön!@50.61", start: 48.99},
{abschnitt: "Verse 3", zeile: "Wer@52.23 trägt@52.79 Blau?@53.13 Wer@53.73 trägt@54.01 Blau?@54.35", start: 52.23},
{abschnitt: "Verse 3", zeile: "Blau@55.25 wie@55.97 Pinos@56.13 Mütze!@56.69", start: 55.25},
{abschnitt: "Verse 3", zeile: "Blau@57.61 wie@58.69 Pinos@59.07 Mütze!@60.23", start: 57.61},
@ -36,7 +36,7 @@ export const DE: {dauer: number; zeilen: Zeile[]} = {
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Zeig,@101.73 zeig,@102.49 zeig@103.01 mal@103.33 hin!@103.55", start: 101.73},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Such@104.27 die@104.49 Farben,@104.73 schau@105.51 gut@105.75 hin!@106.03", start: 104.27},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Rot@106.55 und@106.93 Gelb@107.21 und@107.65 Blau@107.81 und@108.25 Grün,@108.43", start: 106.55},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "alle@109.15 Farben_\u0001@109.39 das@110.93 ist@111.13 schön!@111.37", start: 109.15},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "alle@109.15 Farben_–@109.39 das@110.93 ist@111.13 schön!@111.37", start: 109.15},
],
};
@ -81,35 +81,35 @@ export const ES: {dauer: number; zeilen: Zeile[]} = {
export const FR: {dauer: number; zeilen: Zeile[]} = {
dauer: 131.97,
zeilen: [
{abschnitt: "Chorus", zeile: "Montre,@10.27 montre,@11.17 montre_\u0001@11.73", start: 10.27},
{abschnitt: "Chorus", zeile: "Cherche@12.41 les@12.59 couleurs,@13.23 regarde_\u0001@13.91", start: 12.41},
{abschnitt: "Chorus", zeile: "Montre,@10.27 montre,@11.17 montre_!@11.73", start: 10.27},
{abschnitt: "Chorus", zeile: "Cherche@12.41 les@12.59 couleurs,@13.23 regarde_!@13.91", start: 12.41},
{abschnitt: "Chorus", zeile: "Rouge,@14.61 jaune,@15.27 bleu@15.95 et@16.35 vert,@16.75", start: 14.61},
{abschnitt: "Chorus", zeile: "que@17.15 de@17.25 couleurs_\u0001@17.76 c'est@18.28 super_\u0001@18.79", start: 17.15},
{abschnitt: "Verse 1", zeile: "Qui@20.21 porte@20.63 du@21.07 rouge_\u0001@21.45", start: 20.21},
{abschnitt: "Verse 1", zeile: "Les@22.43 bottes@22.63 rouges@22.95 de@23.39 Noa_\u0001@23.71", start: 22.43},
{abschnitt: "Verse 1", zeile: "Les@24.43 bottes@25.09 rouges@25.39 de@26.63 Noa_\u0001@26.91", start: 24.43},
{abschnitt: "Verse 2", zeile: "Qui@28.49 porte@29.29 du@30.91 jaune_\u0001@31.31", start: 28.49},
{abschnitt: "Verse 2", zeile: "La@32.41 veste@32.49 jaune@32.81 de@33.39 Noa_\u0001@33.61", start: 32.41},
{abschnitt: "Verse 2", zeile: "La@34.37 veste@34.97 jaune@35.31 de@36.33 Noa_\u0001@36.81", start: 34.37},
{abschnitt: "Chorus", zeile: "Montre,@40.23 montre,@40.91 montre_\u0001@41.41", start: 40.23},
{abschnitt: "Chorus", zeile: "Cherche@42.13 les@42.23 couleurs,@42.87 regarde_\u0001@43.59", start: 42.13},
{abschnitt: "Chorus", zeile: "que@17.15 de@17.25 couleurs_–@17.76 c'est@18.28 super_!@18.79", start: 17.15},
{abschnitt: "Verse 1", zeile: "Qui@20.21 porte@20.63 du@21.07 rouge_?@21.45", start: 20.21},
{abschnitt: "Verse 1", zeile: "Les@22.43 bottes@22.63 rouges@22.95 de@23.39 Noa_!@23.71", start: 22.43},
{abschnitt: "Verse 1", zeile: "Les@24.43 bottes@25.09 rouges@25.39 de@26.63 Noa_!@26.91", start: 24.43},
{abschnitt: "Verse 2", zeile: "Qui@28.49 porte@29.29 du@30.91 jaune_?@31.31", start: 28.49},
{abschnitt: "Verse 2", zeile: "La@32.41 veste@32.49 jaune@32.81 de@33.39 Noa_!@33.61", start: 32.41},
{abschnitt: "Verse 2", zeile: "La@34.37 veste@34.97 jaune@35.31 de@36.33 Noa_!@36.81", start: 34.37},
{abschnitt: "Chorus", zeile: "Montre,@40.23 montre,@40.91 montre_!@41.41", start: 40.23},
{abschnitt: "Chorus", zeile: "Cherche@42.13 les@42.23 couleurs,@42.87 regarde_!@43.59", start: 42.13},
{abschnitt: "Chorus", zeile: "Rouge,@44.21 jaune,@44.97 bleu@45.63 et@46.01 vert,@46.41", start: 44.21},
{abschnitt: "Chorus", zeile: "que@46.81 de@46.93 couleurs_\u0001@47.44 c'est@47.96 super_\u0001@48.47", start: 46.81},
{abschnitt: "Verse 3", zeile: "Qui@49.29 porte@50.29 du@50.73 bleu_\u0001@51.09", start: 49.29},
{abschnitt: "Verse 3", zeile: "Le@51.91 bonnet@52.27 bleu@52.67 de@53.19 Pino_\u0001@53.33", start: 51.91},
{abschnitt: "Verse 3", zeile: "Le@54.11 bonnet@54.73 bleu@55.19 de@56.25 Pino_\u0001@56.53", start: 54.11},
{abschnitt: "Verse 4", zeile: "Qui@59.15 porte@59.87 du@60.59 vert_\u0001@61.03", start: 59.15},
{abschnitt: "Verse 4", zeile: "L'écharpe@61.66 verte@62.30 de@62.93 Lulu_\u0001@63.21", start: 61.66},
{abschnitt: "Verse 4", zeile: "L'écharpe@64.03 verte@64.85 de@65.67 Lulu_\u0001@66.45", start: 64.03},
{abschnitt: "Break: call and response", zeile: "Où@68.61 est@69.33 le@69.55 rouge_\u0001@69.73", start: 68.61},
{abschnitt: "Break: call and response", zeile: "Où@70.27 est@70.51 le@70.73 jaune_\u0001@70.95", start: 70.27},
{abschnitt: "Break: call and response", zeile: "Où@71.49 est@71.73 le@72.01 bleu_\u0001@72.19", start: 71.49},
{abschnitt: "Break: call and response", zeile: "Où@72.69 est@72.93 le@73.17 vert_\u0001@73.39", start: 72.69},
{abschnitt: "Break: call and response", zeile: "Et@73.77 maintenant_\u0001@74.09 le@75.41 marron_\u0001@75.57", start: 73.77},
{abschnitt: "Break: call and response", zeile: "Où@76.69 est@77.59 le@77.89 marron_\u0001@78.09", start: 76.69},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Montre,@99.21 montre,@100.11 montre_\u0001@100.61", start: 99.21},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Cherche@101.27 les@101.49 couleurs,@102.09 regarde_\u0001@102.83", start: 101.27},
{abschnitt: "Chorus", zeile: "que@46.81 de@46.93 couleurs_–@47.44 c'est@47.96 super_!@48.47", start: 46.81},
{abschnitt: "Verse 3", zeile: "Qui@49.29 porte@50.29 du@50.73 bleu_?@51.09", start: 49.29},
{abschnitt: "Verse 3", zeile: "Le@51.91 bonnet@52.27 bleu@52.67 de@53.19 Pino_!@53.33", start: 51.91},
{abschnitt: "Verse 3", zeile: "Le@54.11 bonnet@54.73 bleu@55.19 de@56.25 Pino_!@56.53", start: 54.11},
{abschnitt: "Verse 4", zeile: "Qui@59.15 porte@59.87 du@60.59 vert_?@61.03", start: 59.15},
{abschnitt: "Verse 4", zeile: "L'écharpe@61.66 verte@62.30 de@62.93 Lulu_!@63.21", start: 61.66},
{abschnitt: "Verse 4", zeile: "L'écharpe@64.03 verte@64.85 de@65.67 Lulu_!@66.45", start: 64.03},
{abschnitt: "Break: call and response", zeile: "Où@68.61 est@69.33 le@69.55 rouge_?@69.73", start: 68.61},
{abschnitt: "Break: call and response", zeile: "Où@70.27 est@70.51 le@70.73 jaune_?@70.95", start: 70.27},
{abschnitt: "Break: call and response", zeile: "Où@71.49 est@71.73 le@72.01 bleu_?@72.19", start: 71.49},
{abschnitt: "Break: call and response", zeile: "Où@72.69 est@72.93 le@73.17 vert_?@73.39", start: 72.69},
{abschnitt: "Break: call and response", zeile: "Et@73.77 maintenant_:@74.09 le@75.41 marron_!@75.57", start: 73.77},
{abschnitt: "Break: call and response", zeile: "Où@76.69 est@77.59 le@77.89 marron_?@78.09", start: 76.69},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Montre,@99.21 montre,@100.11 montre_!@100.61", start: 99.21},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Cherche@101.27 les@101.49 couleurs,@102.09 regarde_!@102.83", start: 101.27},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "Rouge,@103.45 jaune,@104.07 bleu@104.83 et@105.23 vert,@105.61", start: 103.45},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "que@105.99 de@106.13 couleurs_\u0001@106.90 c'est@107.68 super_\u0001@108.45", start: 105.99},
{abschnitt: "Chorus, softer, slowing down at the end", zeile: "que@105.99 de@106.13 couleurs_–@106.90 c'est@107.68 super_!@108.45", start: 105.99},
],
};

View file

@ -0,0 +1,133 @@
import type {Zeile} from '../EinfachesLied';
// Zeiten der Suno-Aufnahmen (lied04-<sprache>.mp3), am 08.11.2026 mit faster-whisper (small) gemessen, +0,43 s,
// Text aus drehbuecher/lieder/lied04-koerperteile/<sprache>.md (Suno-Text). Erzeugt, nicht von Hand ändern.
// de: 175 von 187 Wörtern direkt erkannt, Rest geschätzt
export const DE: {dauer: number; zeilen: Zeile[]} = {
dauer: 136.80,
zeilen: [
{abschnitt: "Chorus", zeile: "Wer@9.67 hat@10.33 den@10.67 längsten@10.99 Hals?@11.47", start: 9.67},
{abschnitt: "Chorus", zeile: "Lulu,@12.08 Lulu,@12.70 tipp,@13.31 tipp,@13.91 tipp!@14.17", start: 12.08},
{abschnitt: "Chorus", zeile: "Das@14.57 ist@15.09 mein@15.25 Körper,@15.39 schau@16.07 mal@16.27 an,@16.53", start: 14.57},
{abschnitt: "Chorus", zeile: "tipp,@17.01 tipp,@17.65 tipp,@17.95 wer@18.21 tippen@18.41 kann!@18.97", start: 17.01},
{abschnitt: "Verse 1", zeile: "Wo@20.13 sind@20.61 meine@20.89 Ohren?@21.43", start: 20.13},
{abschnitt: "Verse 1", zeile: "Tipp,@22.91 tipp@23.33 auf@23.57 die@23.77 Ohren!@23.99", start: 22.91},
{abschnitt: "Verse 1", zeile: "Tipp,@25.33 tipp@25.99 auf@26.63 die@27.07 Ohren!@27.49", start: 25.33},
{abschnitt: "Verse 2", zeile: "Wo@29.89 sind@30.53 meine@30.83 Hände?@31.37", start: 29.89},
{abschnitt: "Verse 2", zeile: "Tipp,@32.85 tipp@33.17 auf@33.51 die@33.69 Hände!@33.91", start: 32.85},
{abschnitt: "Verse 2", zeile: "Tipp,@34.47 tipp@35.87 auf@36.63 die@36.95 Hände!@37.41", start: 34.47},
{abschnitt: "Chorus", zeile: "Wer@39.51 hat@40.15 den@40.51 längsten@40.81 Hals?@41.31", start: 39.51},
{abschnitt: "Chorus", zeile: "Lulu,@41.92 Lulu,@42.52 tipp,@43.13 tipp,@43.75 tipp!@43.97", start: 41.92},
{abschnitt: "Chorus", zeile: "Das@44.47 ist@44.93 mein@45.07 Körper,@45.23 schau@45.91 mal@46.11 an,@46.39", start: 44.47},
{abschnitt: "Chorus", zeile: "tipp,@46.59 tipp,@46.79 tipp,@47.47 wer@47.99 tippen@48.21 kann!@48.79", start: 46.59},
{abschnitt: "Verse 3", zeile: "Wo@49.83 sind@50.47 meine@50.73 Beine?@51.25", start: 49.83},
{abschnitt: "Verse 3", zeile: "Tipp,@52.39 tipp@53.05 auf@53.41 die@53.57 Beine!@53.77", start: 52.39},
{abschnitt: "Verse 3", zeile: "Tipp,@54.39 tipp@55.81 auf@56.25 die@56.81 Beine!@57.37", start: 54.39},
{abschnitt: "Verse 4", zeile: "Wo@59.53 sind@60.33 meine@60.65 Arme?@61.19", start: 59.53},
{abschnitt: "Verse 4", zeile: "Tipp,@62.37 tipp@62.93 auf@63.31 die@63.51 Arme!@63.73", start: 62.37},
{abschnitt: "Verse 4", zeile: "Tipp,@64.31 tipp@65.61 auf@66.31 die@66.77 Arme!@67.23", start: 64.31},
{abschnitt: "Bridge, speeding up", zeile: "Tipp@68.95 die@69.75 Nase,@69.93 tipp@70.69 den@70.95 Bauch,@71.15", start: 68.95},
{abschnitt: "Bridge, speeding up", zeile: "Hals@71.61 und@72.19 Ohren,@72.43 Hände@73.23 auch!@73.51", start: 71.61},
{abschnitt: "Bridge, speeding up", zeile: "Tipp@74.03 die@74.69 Füße,@74.89 tipp@75.71 den@75.91 Zeh,@76.18", start: 74.03},
{abschnitt: "Bridge, speeding up", zeile: "schneller,@76.45 schneller_–@77.43 juchhe!@78.20", start: 76.45},
{abschnitt: "Bridge, faster", zeile: "Tipp@78.97 die@79.63 Nase,@79.79 tipp@80.59 den@80.81 Bauch,@81.01", start: 78.97},
{abschnitt: "Bridge, faster", zeile: "Hals@81.47 und@82.05 Ohren,@82.27 Hände@83.09 auch!@83.39", start: 81.47},
{abschnitt: "Bridge, faster", zeile: "Tipp@83.89 die@84.49 Füße,@84.69 tipp@85.53 den@85.73 Zeh,@85.99", start: 83.89},
{abschnitt: "Bridge, faster", zeile: "schneller,@86.25 schneller_–@87.29 juchhe!@88.04", start: 86.25},
{abschnitt: "Bridge, slow and calm", zeile: "Tipp@88.79 die@89.41 Nase,@89.63 tipp@90.45 den@90.65 Bauch,@90.93", start: 88.79},
{abschnitt: "Bridge, slow and calm", zeile: "Hals@91.49 und@91.91 Ohren,@92.11 Hände@92.77 auch!@93.29", start: 91.49},
{abschnitt: "Bridge, slow and calm", zeile: "Tipp@93.87 die@94.39 Füße,@94.59 tipp@95.45 den@95.65 Zeh,@96.04", start: 93.87},
{abschnitt: "Bridge, slow and calm", zeile: "langsam,@96.43 langsam,@97.41 wie@97.85 im@98.25 Schnee.@98.57", start: 96.43},
{abschnitt: "Chorus, softer, slowing down", zeile: "Wer@113.89 hat@114.61 den@114.97 längsten@115.25 Hals?@115.73", start: 113.89},
{abschnitt: "Chorus, softer, slowing down", zeile: "Lulu,@116.28 Lulu,@116.82 tipp,@117.37 tipp,@118.29 tipp!@118.45", start: 116.28},
{abschnitt: "Chorus, softer, slowing down", zeile: "Das@118.81 ist@119.39 mein@119.53 Körper,@119.69 schau@120.35 mal@120.57 an,@120.85", start: 118.81},
{abschnitt: "Chorus, softer, slowing down", zeile: "tipp,@121.29 tipp,@121.91 tipp,@122.19 wer@122.51 tippen@122.71 kann!@123.29", start: 121.29},
],
};
// es: 145 von 171 Wörtern direkt erkannt, Rest geschätzt
export const ES: {dauer: number; zeilen: Zeile[]} = {
dauer: 122.04,
zeilen: [
{abschnitt: "Chorus", zeile: "¿Quién@2.87 tiene@3.51 el@3.93 cuello@4.35 más@4.65 largo?@4.93", start: 2.87},
{abschnitt: "Chorus", zeile: "Lulu,@6.13 Lulu,@6.23 ¡toc,@6.91 toc,@7.31 toc!@7.43", start: 6.13},
{abschnitt: "Chorus", zeile: "Este@7.99 es@8.33 mi@8.53 cuerpo:@8.65 ¡a@9.07 tocar!@9.51", start: 7.99},
{abschnitt: "Chorus", zeile: "Toc,@10.07 toc,@10.89 toc,@11.17 ¡y@11.69 a@11.89 jugar!@12.03", start: 10.07},
{abschnitt: "Verse 1", zeile: "¿Dónde@12.51 están@13.39 mis@13.85 orejas?@14.43", start: 12.51},
{abschnitt: "Verse 1", zeile: "¡Toc,@15.47 toc,@16.01 mis@16.57 orejas!@16.97", start: 15.47},
{abschnitt: "Verse 1", zeile: "¡Toc,@17.93 toc,@18.45 mis@19.03 orejas!@19.47", start: 17.93},
{abschnitt: "Verse 2", zeile: "¿Dónde@20.43 están@20.79 mis@21.19 manos?@21.53", start: 20.43},
{abschnitt: "Verse 2", zeile: "¡Toc,@22.77 toc,@23.33 mis@23.73 manos!@23.93", start: 22.77},
{abschnitt: "Verse 2", zeile: "¡Toc,@24.69 toc,@25.75 mis@26.21 manos!@26.41", start: 24.69},
{abschnitt: "Chorus", zeile: "¿Quién@27.21 tiene@28.21 el@28.63 cuello@29.05 más@29.27 largo?@29.55", start: 27.21},
{abschnitt: "Chorus", zeile: "Lulu,@29.99 Lulu,@30.73 ¡toc,@31.43 toc,@31.95 toc!@32.05", start: 29.99},
{abschnitt: "Chorus", zeile: "Este@32.61 es@32.93 mi@33.13 cuerpo:@33.25 ¡a@33.65 tocar!@34.07", start: 32.61},
{abschnitt: "Chorus", zeile: "Toc,@34.59 toc,@35.49 toc,@35.73 ¡y@36.23 a@36.43 jugar!@36.57", start: 34.59},
{abschnitt: "Verse 3", zeile: "¿Dónde@37.07 están@37.89 mis@38.35 piernas?@38.65", start: 37.07},
{abschnitt: "Verse 3", zeile: "¡Toc,@40.01 toc,@40.51 mis@40.93 piernas!@41.07", start: 40.01},
{abschnitt: "Verse 3", zeile: "¡Toc,@42.41 toc,@42.87 mis@43.35 piernas!@43.51", start: 42.41},
{abschnitt: "Verse 4", zeile: "¿Dónde@44.77 están@45.23 mis@45.67 brazos?@45.99", start: 44.77},
{abschnitt: "Verse 4", zeile: "¡Toc,@47.27 toc,@47.75 mis@48.23 brazos!@48.39", start: 47.27},
{abschnitt: "Verse 4", zeile: "¡Toc,@49.75 toc,@50.17 mis@50.71 brazos!@50.83", start: 49.75},
{abschnitt: "Bridge, speeding up", zeile: "Nariz@51.97 y@52.47 barriga:@52.67 ¡toc,@53.31 toc!@54.07", start: 51.97},
{abschnitt: "Bridge, speeding up", zeile: "Cuello,@54.43 orejas,@54.79 manos:@55.15 ¡toc!@55.63", start: 54.43},
{abschnitt: "Bridge, speeding up", zeile: "Pies@56.91 y@57.29 deditos:@57.53 ¡toc,@58.09 toc!@58.87", start: 56.91},
{abschnitt: "Bridge, speeding up", zeile: "¡Más@59.19 rápido,@59.43 más!@60.35 ¡Yupi!@60.93", start: 59.19},
{abschnitt: "Bridge, faster", zeile: "Nariz@61.79 y@62.15 barriga:@62.39 ¡toc,@62.99 toc!@63.71", start: 61.79},
{abschnitt: "Bridge, faster", zeile: "Cuello,@64.09 orejas,@64.47 manos:@64.85 ¡toc!@65.29", start: 64.09},
{abschnitt: "Bridge, faster", zeile: "Pies@66.65 y@66.99 deditos:@67.21 ¡toc,@67.75 toc!@68.51", start: 66.65},
{abschnitt: "Bridge, faster", zeile: "¡Más@68.83 rápido,@69.09 más!@70.45 ¡Yupi!@70.63", start: 68.83},
{abschnitt: "Bridge, slow and calm", zeile: "Nariz@71.43 y@71.79 barriga:@72.05 ¡toc,@72.69 toc!@73.43", start: 71.43},
{abschnitt: "Bridge, slow and calm", zeile: "Cuello,@73.79 orejas,@74.15 manos:@74.51 ¡toc!@74.95", start: 73.79},
{abschnitt: "Bridge, slow and calm", zeile: "Pies@76.27 y@76.69 deditos:@76.85 ¡toc,@77.37 toc!@78.15", start: 76.27},
{abschnitt: "Bridge, slow and calm", zeile: "Despacio,@78.53 como@79.33 la@79.73 nieve.@79.99", start: 78.53},
{abschnitt: "Chorus, softer, slowing down", zeile: "¿Quién@84.37 tiene@88.75 el@93.13 cuello@97.51 más@101.89 largo?@103.41", start: 84.37},
{abschnitt: "Chorus, softer, slowing down", zeile: "Lulu,@104.93 Lulu,@106.45 ¡toc,@107.97 toc,@109.73 toc!@110.13", start: 104.93},
{abschnitt: "Chorus, softer, slowing down", zeile: "Este@110.53 es@110.93 mi@111.33 cuerpo:@111.73 ¡a@112.13 tocar!@112.53", start: 110.53},
{abschnitt: "Chorus, softer, slowing down", zeile: "Toc,@112.93 toc,@113.33 toc,@113.73 ¡y@114.13 a@114.53 jugar!@114.93", start: 112.93},
],
};
// fr: 169 von 197 Wörtern direkt erkannt, Rest geschätzt
export const FR: {dauer: number; zeilen: Zeile[]} = {
dauer: 135.76,
zeilen: [
{abschnitt: "Chorus", zeile: "Qui@5.19 a@5.63 le@6.05 cou@6.35 le@6.65 plus@6.83 long_?@7.13", start: 5.19},
{abschnitt: "Chorus", zeile: "Lulu,@7.81 Lulu,@8.49 toc,@9.17 toc,@9.49 toc_!@9.73", start: 7.81},
{abschnitt: "Chorus", zeile: "Voilà@10.33 mon@10.43 corps,@10.81 regarde-moi,@11.82", start: 10.33},
{abschnitt: "Chorus", zeile: "toc,@12.83 toc,@13.17 toc,@13.47 vas-y,@13.94 à@14.41 toi_!@14.51", start: 12.83},
{abschnitt: "Verse 1", zeile: "Où@15.27 sont@15.51 donc@15.69 mes@15.87 oreilles_?@16.07", start: 15.27},
{abschnitt: "Verse 1", zeile: "Toc,@17.37 toc@18.03 sur@18.27 mes@18.41 oreilles_!@18.59", start: 17.37},
{abschnitt: "Verse 1", zeile: "Toc,@20.13 toc@20.79 sur@21.63 mes@21.87 oreilles_!@22.13", start: 20.13},
{abschnitt: "Verse 2", zeile: "Où@24.85 sont@25.29 donc@25.47 mes@25.67 deux@25.89 mains_?@26.13", start: 24.85},
{abschnitt: "Verse 2", zeile: "Toc,@27.15 toc@27.79 sur@28.03 mes@28.19 deux@28.37 mains_!@28.59", start: 27.15},
{abschnitt: "Verse 2", zeile: "Toc,@29.43 toc@30.59 sur@31.55 mes@31.69 deux@31.97 mains_!@32.29", start: 29.43},
{abschnitt: "Chorus", zeile: "Qui@34.53 a@35.07 le@35.45 cou@35.72 le@35.99 plus@36.23 long_?@36.49", start: 34.53},
{abschnitt: "Chorus", zeile: "Lulu,@37.17 Lulu,@37.85 toc,@38.53 toc,@39.03 toc_!@39.11", start: 37.17},
{abschnitt: "Chorus", zeile: "Voilà@39.53 mon@39.83 corps,@40.19 regarde-moi,@41.19", start: 39.53},
{abschnitt: "Chorus", zeile: "toc,@42.19 toc,@42.65 toc,@42.85 vas-y,@43.32 à@43.79 toi_!@43.89", start: 42.19},
{abschnitt: "Verse 3", zeile: "Où@44.61 sont@44.81 donc@45.07 mes@45.29 deux@45.47 jambes_?@45.73", start: 44.61},
{abschnitt: "Verse 3", zeile: "Toc,@46.87 toc@47.47 sur@47.57 mes@47.79 deux@47.93 jambes_!@48.21", start: 46.87},
{abschnitt: "Verse 3", zeile: "Toc,@49.55 toc@50.11 sur@51.03 mes@51.27 deux@51.55 jambes_!@51.87", start: 49.55},
{abschnitt: "Verse 4", zeile: "Où@54.32 sont@54.59 donc@54.85 mes@55.03 deux@55.23 bras_?@55.49", start: 54.32},
{abschnitt: "Verse 4", zeile: "Toc,@56.71 toc@57.17 sur@57.35 mes@57.59 deux@57.73 bras_!@57.95", start: 56.71},
{abschnitt: "Verse 4", zeile: "Toc,@58.75 toc@59.97 sur@60.83 mes@61.05 deux@61.35 bras_!@61.63", start: 58.75},
{abschnitt: "Bridge, speeding up", zeile: "Nez,@62.59 ventre,@63.55 cou_–@64.23 toc,@64.91 toc,@65.31 toc_!@65.49", start: 62.59},
{abschnitt: "Bridge, speeding up", zeile: "Oreilles,@65.83 mains_–@66.39 toc,@67.35 toc,@67.71 toc_!@67.93", start: 65.83},
{abschnitt: "Bridge, speeding up", zeile: "Pieds@68.15 et@68.37 orteils_–@68.73 toc,@69.77 toc,@70.19 toc_!@70.59", start: 68.15},
{abschnitt: "Bridge, speeding up", zeile: "Vite,@71.43 vite_–@72.11 youpi_!@72.54", start: 71.43},
{abschnitt: "Bridge, faster", zeile: "Nez,@72.96 ventre,@73.39 cou_–@74.00 toc,@74.61 toc,@74.95 toc_!@75.29", start: 72.96},
{abschnitt: "Bridge, faster", zeile: "Oreilles,@75.61 mains_–@76.19 toc,@77.07 toc,@77.49 toc_!@77.77", start: 75.61},
{abschnitt: "Bridge, faster", zeile: "Pieds@77.98 et@78.19 orteils_–@78.49 toc,@79.53 toc,@79.93 toc_!@80.31", start: 77.98},
{abschnitt: "Bridge, faster", zeile: "Vite,@81.09 vite_–@81.89 youpi_!@82.30", start: 81.09},
{abschnitt: "Bridge, slow and calm", zeile: "Nez,@82.72 ventre,@83.13 cou_–@83.76 toc,@84.39 toc,@84.73 toc_!@85.09", start: 82.72},
{abschnitt: "Bridge, slow and calm", zeile: "Oreilles,@85.33 mains_–@85.97 toc,@86.77 toc,@87.29 toc_!@87.47", start: 85.33},
{abschnitt: "Bridge, slow and calm", zeile: "Pieds@87.70 et@87.93 orteils_–@88.31 toc,@89.05 toc,@89.69 toc_!@89.89", start: 87.7},
{abschnitt: "Bridge, slow and calm", zeile: "Tout@90.83 doux,@91.14 sans@91.44 se@91.75 presser.@91.97", start: 90.83},
{abschnitt: "Chorus, softer, slowing down", zeile: "Qui@104.41 a@104.89 le@105.33 cou@105.59 le@105.85 plus@106.11 long_?@106.39", start: 104.41},
{abschnitt: "Chorus, softer, slowing down", zeile: "Lulu,@107.06 Lulu,@107.74 toc,@108.41 toc,@108.83 toc_!@108.95", start: 107.06},
{abschnitt: "Chorus, softer, slowing down", zeile: "Voilà@109.47 mon@109.65 corps,@110.05 regarde-moi,@110.78", start: 109.47},
{abschnitt: "Chorus, softer, slowing down", zeile: "toc,@111.51 toc,@112.39 toc,@112.69 vas-y,@113.16 à@113.63 toi_!@113.75", start: 111.51},
],
};

View file

@ -0,0 +1,94 @@
import React from 'react';
import {Figur} from '../../baukasten/figur';
import {punkt} from '../../baukasten/helfer';
import {BODEN} from '../../baukasten/orte';
import {SPRACHE} from '../../baukasten/sprache';
import {type Bild, EinfachesLied, type LiedDaten, PLATZ, type Punkt, type Zeile, wortZeit} from '../einfach/EinfachesLied';
import {DE, ES, FR} from '../einfach/daten/lied04';
// Liedvideo „Wer hat den längsten Hals?“ (Pinos Liederbuch, Lied 4: Körperteile) in DE/ES/FR.
// Refrain: Lulu streckt den Hals. Strophen (Ohren, Hände, Beine, Arme): nah bei Noa, die Stellen leuchten,
// die Karte zeigt eine kleine Noa mit der leuchtenden Stelle. Turbo-Teil (3×): jedes genannte Körperteil
// leuchtet zu seinem Wort, im dritten Durchgang langsam. Drehbuch drehbuecher/lieder/lied04-koerperteile/.
// Körperteile in noa_A3_lachen (Leinwand = Bild + 339/156, gemessen)
const TEIL: Record<string, [number, number][]> = {
ohren: [[607, 306], [809, 306]],
haende: [[629, 576], [809, 551]],
beine: [[684, 616], [744, 616]],
arme: [[629, 476], [799, 466]],
nase: [[734, 296]],
bauch: [[709, 486]],
hals: [[709, 361]],
fuesse: [[684, 691], [754, 691]],
zeh: [[759, 721]],
};
const FARBE = '#d9482b'; // kräftiges Rot-Orange: hebt sich von Jacke und Gesicht ab
const WOERTER: [RegExp, string][] = [
[/^(ohren|orejas|oreilles)/i, 'ohren'],
[/^(h[aä]nde|manos|mains)/i, 'haende'],
[/^(beine|piernas|jambes)/i, 'beine'],
[/^(arme|brazos|bras)$/i, 'arme'],
[/^(nase|nariz|nez)/i, 'nase'],
[/^(bauch|barriga|ventre|tripa)/i, 'bauch'],
[/^(hals|cuello|cou)$/i, 'hals'],
[/^(f[uü](ß|ss)e|pies|pieds)/i, 'fuesse'],
[/^(zeh|deditos|orteils)/i, 'zeh'],
];
const teilVon = (wort: string) => WOERTER.find(([re]) => re.test(wort.replace(/[^\p{L}]/gu, '')))?.[1];
const anNoa = (teil: string): Punkt[] => TEIL[teil].map(([cx, cy]) => punkt('noa', PLATZ.noa, BODEN, cx, cy));
// Karte: kleine Noa, die genannte Stelle leuchtet
const NoaKarte: React.FC<{teil: string}> = ({teil}) => (
<div style={{position: 'relative', width: 204, height: 204}}>
<Figur pose="noa_A3_lachen" x={102} y={198} hoehe={180} schatten={false} />
{TEIL[teil].map(([cx, cy], k) => {
const p = punkt('noa', 102, 198, cx, cy, 180);
return <div key={k} style={{position: 'absolute', left: p.x - 16, top: p.y - 16, width: 32, height: 32, borderRadius: '50%', border: `5px solid ${FARBE}`, background: `${FARBE}66`}} />;
})}
</div>
);
const LIEDER = {de: DE, es: ES, fr: FR};
const TITEL = {
de: {titel: 'Wer hat den\nlängsten Hals?', zeile: 'Wer hat den längsten Hals?'},
es: {titel: '¿Quién tiene el\ncuello más largo?', zeile: '¿Quién tiene el cuello más largo?'},
fr: {titel: 'Qui a le cou\nle plus long ?', zeile: 'Qui a le cou le plus long ?'},
};
const DATEN: LiedDaten = {...LIEDER[SPRACHE], datei: `musik/lieder/lied04-${SPRACHE}.mp3`, titel: TITEL[SPRACHE].titel, zeileTitel: TITEL[SPRACHE].zeile};
const lage = (i: number) => {
const z = DATEN.zeilen;
let k = i;
while (k > 0 && z[k - 1].abschnitt === z[i].abschnitt) k--;
return i - k;
};
const NOA_NAH = {x: PLATZ.noa, y: 765, z: 1.75}; // ganze Noa über dem Mitlesetext
const LULU_HALS = punkt('lulu', PLATZ.lulu, BODEN, 322 + 320, 23 + 230);
const szene = (i: number, z: Zeile): Bild => {
const a = z.abschnitt.toLowerCase();
const n = lage(i);
const woerter = z.zeile.split(' ').map((w) => w.split('@')[0]);
if (a.startsWith('chorus')) {
if (n === 0) return {kamera: {x: PLATZ.lulu - 60, y: 420, z: 1.5}, luluStreckt: true, lulu: 'lulu_A3_lachen'};
if (n === 1) return {leuchten: [{...LULU_HALS, farbe: FARBE, r: 90}]};
return {};
}
if (a.startsWith('verse')) {
const teil = woerter.map(teilVon).find(Boolean) ?? 'ohren';
if (n === 0) return {kamera: NOA_NAH, noa: i % 2 ? 'noa_A5_blick-links' : 'noa_A6_blick-rechts', ruhig: true, karte: <NoaKarte teil={teil} />};
return {kamera: NOA_NAH, leuchten: anNoa(teil).map((p) => ({...p, farbe: FARBE, r: 46})), karte: <NoaKarte teil={teil} />};
}
if (a.startsWith('bridge')) {
const leuchten = woerter.flatMap((w, k) => {
const teil = teilVon(w);
return teil ? anNoa(teil).map((p) => ({...p, farbe: FARBE, r: 40, ab: wortZeit(z, k) - 0.05})) : [];
});
return {kamera: {x: PLATZ.noa - 40, y: 720, z: 1.5}, leuchten, ruhig: a.includes('slow')};
}
return {ruhig: true};
};
export const LIED04_DAUER = Math.round(DATEN.dauer * 30);
export const Lied04: React.FC = () => <EinfachesLied daten={DATEN} szene={szene} />;