From 6489b61dc3d46cd75c2e79cc2910e0e55c9e491f Mon Sep 17 00:00:00 2001 From: Lara Date: Sun, 8 Nov 2026 19:36:19 +0000 Subject: [PATCH] =?UTF-8?q?Liedvideo=20Lied=204=20=E2=80=9EWer=20hat=20den?= =?UTF-8?q?=20l=C3=A4ngsten=20Hals=3F=E2=80=9C=20(DE/ES/FR);=20Vorlage:=20?= =?UTF-8?q?kr=C3=A4ftigere=20Leuchtkreise,=20Satzzeichen=20im=20Mitlesetex?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- remotion/src/Root.tsx | 2 + remotion/src/lieder/einfach/EinfachesLied.tsx | 8 +- remotion/src/lieder/einfach/daten/lied02.ts | 60 ++++---- remotion/src/lieder/einfach/daten/lied04.ts | 133 ++++++++++++++++++ remotion/src/lieder/lied04/Lied04.tsx | 94 +++++++++++++ 5 files changed, 264 insertions(+), 33 deletions(-) create mode 100644 remotion/src/lieder/einfach/daten/lied04.ts create mode 100644 remotion/src/lieder/lied04/Lied04.tsx diff --git a/remotion/src/Root.tsx b/remotion/src/Root.tsx index d9b3499..ac4228f 100644 --- a/remotion/src/Root.tsx +++ b/remotion/src/Root.tsx @@ -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 = () => ( <> + diff --git a/remotion/src/lieder/einfach/EinfachesLied.tsx b/remotion/src/lieder/einfach/EinfachesLied.tsx index 23f6973..b923d22 100644 --- a/remotion/src/lieder/einfach/EinfachesLied.tsx +++ b/remotion/src/lieder/einfach/EinfachesLied.tsx @@ -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 = ({x, y, farbe, r = 70, ab, bis}) => { +const Leuchtkreis: React.FC = ({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.mp3), am 08.11.2026 mit faster-whisper (small) gemessen, +0,43 s, +// Text aus drehbuecher/lieder/lied04-koerperteile/.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}, + ], +}; diff --git a/remotion/src/lieder/lied04/Lied04.tsx b/remotion/src/lieder/lied04/Lied04.tsx new file mode 100644 index 0000000..5e8b5e8 --- /dev/null +++ b/remotion/src/lieder/lied04/Lied04.tsx @@ -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 = { + 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}) => ( +
+ + {TEIL[teil].map(([cx, cy], k) => { + const p = punkt('noa', 102, 198, cx, cy, 180); + return
; + })} +
+); + +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: }; + return {kamera: NOA_NAH, leuchten: anNoa(teil).map((p) => ({...p, farbe: FARBE, r: 46})), karte: }; + } + 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 = () => ;