Lulus Hals-Clip ohne Zoom, Noa klatscht im Lied, Nestbau ruhiger
- clipkorrektur.ts: Higgsfield-Kamera zoomt/schwenkt im Clip lulu_C9 (Beine +20 % breiter, 79 px versetzt) – je Clipbild zurückgerechnet, auch die Apfel-Bahn im Maul - neue Pose noa_A_klatschen (Higgsfield, 1,5 Credits, Auftrag cbb2880c), Lied in Folge 1 und 2: Noa klatscht auf jeden zweiten Schlag (klatschFolge) - schwebende Klatsch-Hände wieder entfernt - Folge 2, Nestbau: kein seitliches Hin- und Herrutschen von Noa und Lulu - .gitignore: .env/.env.local (ElevenLabs-Schlüssel) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018MyLusGH2U5AudjoARey3N
This commit is contained in:
parent
7de2b609ba
commit
1db1001dfc
12 changed files with 100 additions and 17 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -15,3 +15,7 @@ node_modules/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
schnitt/ausgabe/
|
schnitt/ausgabe/
|
||||||
schnitt/tmp/
|
schnitt/tmp/
|
||||||
|
|
||||||
|
# Zugangsschlüssel (ElevenLabs u. a.), nie ins Git
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ unter `figuren/bibliothek/`. Die **Clips** (MP4) sind nicht im Git (siehe
|
||||||
| noa_A8_rueckansicht | Rückansicht | 1 | 1,5 | |
|
| noa_A8_rueckansicht | Rückansicht | 1 | 1,5 | |
|
||||||
| noa_A_arm-hoch-winken | rechter Arm hoch, winkend | 1 | 1,5 | |
|
| noa_A_arm-hoch-winken | rechter Arm hoch, winkend | 1 | 1,5 | |
|
||||||
| noa_A_arme-hoch | beide Arme hoch | 1 | 1,5 | |
|
| noa_A_arme-hoch | beide Arme hoch | 1 | 1,5 | |
|
||||||
|
| noa_A_klatschen | klatscht, Fäustlinge vor der Brust (02.11.2026, Nano Banana 2 aus noa_ref_stehend, für das Lied) | 1 | 1,5 | ohne rembg freigestellt |
|
||||||
| noa_A_laterne | Laterne in rechter Hand | 2 | 3 | 1. Versuch ohne Laterne; 2. gespiegelt; Laterne ragt seitlich weit heraus |
|
| noa_A_laterne | Laterne in rechter Hand | 2 | 3 | 1. Versuch ohne Laterne; 2. gespiegelt; Laterne ragt seitlich weit heraus |
|
||||||
| noa_B1_traurig | traurig | 2 | 1,5 | 1. Versuch abgebrochen, erstattet |
|
| noa_B1_traurig | traurig | 2 | 1,5 | 1. Versuch abgebrochen, erstattet |
|
||||||
| noa_B2_erschrocken | kurz erschrocken | 1 | 1,5 | |
|
| noa_B2_erschrocken | kurz erschrocken | 1 | 1,5 | |
|
||||||
|
|
|
||||||
|
|
@ -61,3 +61,4 @@ lulu_B3_schlafen.png 23_e3e6898f-ba75-410d-9488-936dd5af4
|
||||||
lulu_B_kopf-profil.png 23_806c2339-90e8-42af-92b0-36b390e7d
|
lulu_B_kopf-profil.png 23_806c2339-90e8-42af-92b0-36b390e7d
|
||||||
noa_B1_traurig.png 030f14b3-a839-44d0-90bf-5a89e1fc92a9
|
noa_B1_traurig.png 030f14b3-a839-44d0-90bf-5a89e1fc92a9
|
||||||
pino_B3_schlafen.png dc751ba2-c05b-493b-95e1-c92668f1c627
|
pino_B3_schlafen.png dc751ba2-c05b-493b-95e1-c92668f1c627
|
||||||
|
noa_A_klatschen.png cbb2880c-95c7-4276-9cdf-a7eef639c5a7
|
||||||
|
|
|
||||||
|
BIN
figuren/bibliothek/noa_A_klatschen.png
Normal file
BIN
figuren/bibliothek/noa_A_klatschen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
remotion/public/bibliothek/figuren/noa_A_klatschen.webp
Normal file
BIN
remotion/public/bibliothek/figuren/noa_A_klatschen.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 117 KiB |
42
remotion/src/baukasten/clipkorrektur.ts
Normal file
42
remotion/src/baukasten/clipkorrektur.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Korrektur für Clips, in denen die Kamera von Higgsfield leicht zoomt oder schwenkt.
|
||||||
|
// Gemessen an den Beinen (Mitte und Breite) je Clip-Bild, in Pixeln des Clipbildes.
|
||||||
|
// Angewendet wird die Rückrechnung: die Beine bleiben am Platz und gleich breit.
|
||||||
|
|
||||||
|
type Messung = [number, number, number]; // [Clip-Bild (24 fps), Beinmitte x, Beinbreite]
|
||||||
|
|
||||||
|
const MESSUNGEN: Record<string, {bildBreite: number; fussY: number; werte: Messung[]}> = {
|
||||||
|
// Lulu senkt den Hals: Beine werden um 20 % breiter und wandern 79 px zur Seite
|
||||||
|
'lulu_C9_hals-runter': {
|
||||||
|
bildBreite: 662, // Breite des Clipbildes in Pixeln
|
||||||
|
fussY: 659,
|
||||||
|
werte: [
|
||||||
|
[0, 417.5, 211], [16, 417, 210], [20, 417.5, 211], [24, 418.5, 211], [28, 420.5, 213], [32, 423, 214],
|
||||||
|
[36, 426.5, 215], [40, 430, 216], [44, 434, 218], [48, 438, 218], [52, 442.5, 221], [56, 447, 222],
|
||||||
|
[60, 452, 224], [64, 457, 226], [68, 461, 228], [72, 466.5, 231], [76, 470.5, 233], [80, 475, 236],
|
||||||
|
[84, 479.5, 239], [88, 483.5, 241], [92, 487, 244], [96, 490.5, 247], [100, 493.5, 249], [104, 495.5, 251],
|
||||||
|
[108, 496.5, 253], [120, 496.5, 253],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Korrektur = {k: number; mitte: number; ziel: number; fussY: number; bildBreite: number};
|
||||||
|
|
||||||
|
// Für Clip-Bild `b`: Maßstab k und Beinmitte (Ist und Soll), alles in Clip-Pixeln.
|
||||||
|
export const clipKorrektur = (name: string, b: number): Korrektur | null => {
|
||||||
|
const m = MESSUNGEN[name];
|
||||||
|
if (!m) return null;
|
||||||
|
const w = m.werte;
|
||||||
|
const bb = Math.min(w[w.length - 1][0], Math.max(0, b));
|
||||||
|
let i = 0;
|
||||||
|
while (i < w.length - 2 && w[i + 1][0] < bb) i++;
|
||||||
|
const [b0, m0, w0] = w[i];
|
||||||
|
const [b1, m1, w1] = w[i + 1];
|
||||||
|
const t = b1 === b0 ? 0 : (bb - b0) / (b1 - b0);
|
||||||
|
const mitte = m0 + (m1 - m0) * t;
|
||||||
|
const breite = w0 + (w1 - w0) * t;
|
||||||
|
return {k: w[0][2] / breite, mitte, ziel: w[0][1], fussY: m.fussY, bildBreite: m.bildBreite};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Punkt (in Clip-Pixeln) so verschieben, wie die Korrektur das Bild verschiebt
|
||||||
|
export const korrigiere = (kor: Korrektur | null, x: number, y: number) =>
|
||||||
|
kor ? {x: kor.ziel + kor.k * (x - kor.mitte), y: kor.fussY + kor.k * (y - kor.fussY)} : {x, y};
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Freeze, Img, OffthreadVideo, getStaticFiles, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
|
import {Freeze, Img, OffthreadVideo, getStaticFiles, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
|
||||||
|
import {clipKorrektur} from './clipkorrektur';
|
||||||
import {CLIPS, FIGUREN, POSEN} from './posen';
|
import {CLIPS, FIGUREN, POSEN} from './posen';
|
||||||
|
|
||||||
// Figuren aus der Bibliothek (freigestellte Standbilder und Clips).
|
// Figuren aus der Bibliothek (freigestellte Standbilder und Clips).
|
||||||
|
|
@ -149,9 +150,15 @@ export const ClipFigur: React.FC<ClipProps> = ({name, start, hoehe, tempo = 1, s
|
||||||
let t = Math.max(0, (frame - start) * tempo);
|
let t = Math.max(0, (frame - start) * tempo);
|
||||||
t = schleife ? t % (laenge - 1) : Math.min(t, laenge - 1);
|
t = schleife ? t % (laenge - 1) : Math.min(t, laenge - 1);
|
||||||
if (rueckwaerts) t = laenge - 1 - t;
|
if (rueckwaerts) t = laenge - 1 - t;
|
||||||
|
// Zoom/Schwenk der Higgsfield-Kamera im Clip zurückrechnen (Beine bleiben am Platz)
|
||||||
|
const kor = clipKorrektur(name, (t * 24) / fps);
|
||||||
|
const px = kor ? c.b / kor.bildBreite : 1;
|
||||||
|
const korStil: React.CSSProperties = kor
|
||||||
|
? {transformOrigin: `${kor.mitte * px}px ${kor.fussY * px}px`, transform: `translateX(${(kor.ziel - kor.mitte) * px}px) scale(${kor.k})`}
|
||||||
|
: {};
|
||||||
return (
|
return (
|
||||||
<Rahmen {...lage} figur={figur} hoehe={hoehe ?? NOA_HOEHE * GROESSE[figur]}>
|
<Rahmen {...lage} figur={figur} hoehe={hoehe ?? NOA_HOEHE * GROESSE[figur]}>
|
||||||
<div style={{position: 'absolute', left: c.x, top: c.y, width: c.b, height: c.h}}>
|
<div style={{position: 'absolute', left: c.x, top: c.y, width: c.b, height: c.h, ...korStil}}>
|
||||||
<Freeze frame={Math.floor(t)}>
|
<Freeze frame={Math.floor(t)}>
|
||||||
<OffthreadVideo src={staticFile(c.datei)} transparent muted style={{width: '100%', height: '100%'}} />
|
<OffthreadVideo src={staticFile(c.datei)} transparent muted style={{width: '100%', height: '100%'}} />
|
||||||
</Freeze>
|
</Freeze>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import {clipKorrektur, korrigiere} from './clipkorrektur';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {interpolate, useCurrentFrame} from 'remotion';
|
import {interpolate, useCurrentFrame} from 'remotion';
|
||||||
import {kurve} from '../bewegung';
|
import {kurve} from '../bewegung';
|
||||||
|
|
@ -88,6 +89,18 @@ export const luluMaulC9 = (clipBild: number) => {
|
||||||
const [b0, x0, y0] = C9_NASE[i];
|
const [b0, x0, y0] = C9_NASE[i];
|
||||||
const [b1, x1, y1] = C9_NASE[i + 1];
|
const [b1, x1, y1] = C9_NASE[i + 1];
|
||||||
const t = b1 === b0 ? 0 : (b - b0) / (b1 - b0);
|
const t = b1 === b0 ? 0 : (b - b0) / (b1 - b0);
|
||||||
// Maul knapp über der Unterkante der Nase
|
// Maul knapp über der Unterkante der Nase; dieselbe Zoom-Korrektur wie das Clipbild
|
||||||
return {cx: C9.x + (x0 + (x1 - x0) * t) * C9.s, cy: C9.y + (y0 + (y1 - y0) * t - 6) * C9.s};
|
const p = korrigiere(clipKorrektur('lulu_C9_hals-runter', b), x0 + (x1 - x0) * t, y0 + (y1 - y0) * t - 6);
|
||||||
|
return {cx: C9.x + p.x * C9.s, cy: C9.y + p.y * C9.s};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Klatschen im Lied: Noa klatscht auf jeden zweiten Schlag (Schlag 1, 3, 5 … ab Liedbeginn).
|
||||||
|
// Liefert Posenwechsel für die Zeit von `von` bis `bis` (Hände zusammen kurz um den Schlag).
|
||||||
|
export const klatschFolge = (von: number, bis: number, takt: number, basis = 'noa_A3_lachen'): [number, string][] => {
|
||||||
|
const folge: [number, string][] = [];
|
||||||
|
for (let t = takt; t < bis; t += 2 * takt) {
|
||||||
|
if (t - 3 < von) continue;
|
||||||
|
folge.push([t - 3, 'noa_A_klatschen'], [t + 4, basis]);
|
||||||
|
}
|
||||||
|
return folge;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,20 @@ export const POSEN: Record<string, Pose> = {
|
||||||
701
|
701
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"noa_A_klatschen": {
|
||||||
|
"figur": "noa",
|
||||||
|
"datei": "bibliothek/figuren/noa_A_klatschen.webp",
|
||||||
|
"x": 339,
|
||||||
|
"y": 156,
|
||||||
|
"b": 715,
|
||||||
|
"h": 551,
|
||||||
|
"box": [
|
||||||
|
543,
|
||||||
|
165,
|
||||||
|
807,
|
||||||
|
700
|
||||||
|
]
|
||||||
|
},
|
||||||
"noa_A_arme-hoch": {
|
"noa_A_arme-hoch": {
|
||||||
"figur": "noa",
|
"figur": "noa",
|
||||||
"datei": "bibliothek/figuren/noa_A_arme-hoch.webp",
|
"datei": "bibliothek/figuren/noa_A_arme-hoch.webp",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {random, useCurrentFrame} from 'remotion';
|
import {random, useCurrentFrame} from 'remotion';
|
||||||
import {Figur, Kamera} from '../baukasten/figur';
|
import {Figur, Kamera} from '../baukasten/figur';
|
||||||
import {Blende, Vignette} from '../baukasten/helfer';
|
import {Blende, Vignette, klatschFolge} from '../baukasten/helfer';
|
||||||
import {Blume, Klatschen, Laubhaufen} from '../baukasten/natur';
|
import {Blume, Laubhaufen} from '../baukasten/natur';
|
||||||
import {BODEN, Ort} from '../baukasten/orte';
|
import {BODEN, Ort} from '../baukasten/orte';
|
||||||
import {SCHRIFT, Untertitel} from '../baukasten/untertitel';
|
import {SCHRIFT, Untertitel} from '../baukasten/untertitel';
|
||||||
import {TEXTE, plane} from './plan';
|
import {TEXTE, plane} from './plan';
|
||||||
|
|
@ -57,10 +57,13 @@ export const Lied: React.FC = () => {
|
||||||
[z.s4.start, 'pino_A_hinterbeine'],
|
[z.s4.start, 'pino_A_hinterbeine'],
|
||||||
[z.w1.start, 'pino_A3_lachen'],
|
[z.w1.start, 'pino_A3_lachen'],
|
||||||
];
|
];
|
||||||
|
// Noa klatscht im Takt (jeder zweite Schlag), bei „zusammen kriegen wir alles hin“ Arme hoch
|
||||||
const noaPose: [number, string][] = [
|
const noaPose: [number, string][] = [
|
||||||
[0, 'noa_A3_lachen'],
|
[0, 'noa_A3_lachen'],
|
||||||
|
...klatschFolge(z.r1.start, z.r4.start, TAKT),
|
||||||
[z.r4.start, 'noa_A_arme-hoch'],
|
[z.r4.start, 'noa_A_arme-hoch'],
|
||||||
[z.s1.start, 'noa_A3_lachen'],
|
[z.s1.start, 'noa_A3_lachen'],
|
||||||
|
...klatschFolge(z.s1.start, z.w4.start, TAKT),
|
||||||
[z.w4.start, 'noa_A_arme-hoch'],
|
[z.w4.start, 'noa_A_arme-hoch'],
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
|
|
@ -69,7 +72,7 @@ export const Lied: React.FC = () => {
|
||||||
<Ort name="garten_herbst" />
|
<Ort name="garten_herbst" />
|
||||||
<Laubhaufen x={HAUFEN_X + 380} y={BODEN + 6} />
|
<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={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={noaPose} x={980} y={BODEN + wipp(0.3, 10)} drehung={schwank(0, 3)} blende={3} />
|
||||||
<Figur pose={pinoPose} x={760} y={BODEN + wipp(0, 16)} drehung={schwank(1, 4)} stauchY={1 - 0.03 * schlag} 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} />}
|
{f >= z.s4.start && f < z.w1.start && <Blume x={764} y={BODEN - 40} s={0.5} />}
|
||||||
</Kamera>
|
</Kamera>
|
||||||
|
|
@ -85,8 +88,6 @@ export const Lied: React.FC = () => {
|
||||||
<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)}}>
|
<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} ♫
|
♫ {TEXTE.lied} ♫
|
||||||
</div>
|
</div>
|
||||||
{/* Klatsch-Hände: auf jeden zweiten Schlag zum Mitklatschen */}
|
|
||||||
<Klatschen x={960} y={215} takt={TAKT} s={1.3} deckkraft={Math.min(1, f / 20)} />
|
|
||||||
<Vignette />
|
<Vignette />
|
||||||
<Untertitel zeilen={LIED.liste} />
|
<Untertitel zeilen={LIED.liste} />
|
||||||
<Blende dauer={dauer} rein={12} raus={12} />
|
<Blende dauer={dauer} rein={12} raus={12} />
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {random, useCurrentFrame} from 'remotion';
|
import {random, useCurrentFrame} from 'remotion';
|
||||||
import {Figur, Kamera} from '../baukasten/figur';
|
import {Figur, Kamera} from '../baukasten/figur';
|
||||||
import {Blende, Vignette} from '../baukasten/helfer';
|
import {Blende, Vignette, klatschFolge} from '../baukasten/helfer';
|
||||||
import {Klatschen} from '../baukasten/natur';
|
|
||||||
import {BODEN, Ort} from '../baukasten/orte';
|
import {BODEN, Ort} from '../baukasten/orte';
|
||||||
import {SCHRIFT, Untertitel} from '../baukasten/untertitel';
|
import {SCHRIFT, Untertitel} from '../baukasten/untertitel';
|
||||||
import {TEXTE, plane} from './plan';
|
import {TEXTE, plane} from './plan';
|
||||||
|
|
@ -43,11 +42,14 @@ export const Lied: React.FC = () => {
|
||||||
<Figur
|
<Figur
|
||||||
pose={[
|
pose={[
|
||||||
[0, 'noa_A3_lachen'],
|
[0, 'noa_A3_lachen'],
|
||||||
|
// Noa klatscht im Takt (jeder zweite Schlag)
|
||||||
|
...klatschFolge(z.r1.start, z.r4.start, TAKT),
|
||||||
[z.r4.start, 'noa_A_arme-hoch'],
|
[z.r4.start, 'noa_A_arme-hoch'],
|
||||||
]}
|
]}
|
||||||
x={960}
|
x={960}
|
||||||
y={BODEN + wipp(0.3, 10)}
|
y={BODEN + wipp(0.3, 10)}
|
||||||
drehung={schwank(0, 3)}
|
drehung={schwank(0, 3)}
|
||||||
|
blende={3}
|
||||||
/>
|
/>
|
||||||
<Figur pose="pino_A3_lachen" x={720} y={BODEN + wipp(0, 16)} drehung={schwank(1, 4)} stauchY={1 - 0.03 * schlag} />
|
<Figur pose="pino_A3_lachen" x={720} y={BODEN + wipp(0, 16)} drehung={schwank(1, 4)} stauchY={1 - 0.03 * schlag} />
|
||||||
</Kamera>
|
</Kamera>
|
||||||
|
|
@ -59,8 +61,6 @@ export const Lied: React.FC = () => {
|
||||||
<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)}}>
|
<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} ♫
|
♫ {TEXTE.lied} ♫
|
||||||
</div>
|
</div>
|
||||||
{/* Klatsch-Hände: auf jeden zweiten Schlag zum Mitklatschen */}
|
|
||||||
<Klatschen x={960} y={215} takt={TAKT} s={1.3} deckkraft={Math.min(1, f / 20)} />
|
|
||||||
<Vignette />
|
<Vignette />
|
||||||
<Untertitel zeilen={LIED.liste} />
|
<Untertitel zeilen={LIED.liste} />
|
||||||
<Blende dauer={dauer} rein={12} raus={12} />
|
<Blende dauer={dauer} rein={12} raus={12} />
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,8 @@ export const Szene4: React.FC = () => {
|
||||||
const hockeStauch = hockZeiten.reduce((s, [a, b]) => s * (1 - 0.05 * bump(a)) * (1 + 0.03 * bump(b)), 1);
|
const hockeStauch = hockZeiten.reduce((s, [a, b]) => s * (1 - 0.05 * bump(a)) * (1 + 0.03 * bump(b)), 1);
|
||||||
// beim Hinlegen jedes Blatts kurz nach vorn beugen
|
// beim Hinlegen jedes Blatts kurz nach vorn beugen
|
||||||
const beugen = zaehlen.reduce((s, c) => s + Math.max(0, Math.sin(Math.min(1, Math.max(0, (f - c + 8) / 16)) * Math.PI)), 0);
|
const beugen = zaehlen.reduce((s, c) => s + Math.max(0, Math.sin(Math.min(1, Math.max(0, (f - c + 8) / 16)) * Math.PI)), 0);
|
||||||
// beim Nestbau schieben (vor und zurück)
|
// beim Nestbau: früher seitliches Hin- und Herrutschen (wirkte unruhig) – jetzt ruhig, nur die Blätter bewegen sich
|
||||||
const schieben = f > zurueck && f < z.bild4.ende ? Math.sin((f - zurueck) * 0.22) : 0;
|
|
||||||
|
|
||||||
// Pino
|
// Pino
|
||||||
const pinoGehtVon = zumStapel + 40;
|
const pinoGehtVon = zumStapel + 40;
|
||||||
|
|
@ -202,7 +202,7 @@ export const Szene4: React.FC = () => {
|
||||||
kam.y += ruck(f, niesen, 9, 22);
|
kam.y += ruck(f, niesen, 9, 22);
|
||||||
|
|
||||||
const lulu = <Figur pose={luluPose} x={LULU_BAUM_X} y={luluY} stauchY={luluStauch} drehung={luluDreh} />;
|
const lulu = <Figur pose={luluPose} x={LULU_BAUM_X} y={luluY} stauchY={luluStauch} drehung={luluDreh} />;
|
||||||
const luluBeimNest = f >= zurueck && <Figur pose="lulu_A_hals-unten" x={2030} y={BODEN - 4} drehung={schieben * 1.2} />;
|
const luluBeimNest = f >= zurueck && <Figur pose="lulu_A_hals-unten" x={2030} y={BODEN - 4} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -225,10 +225,10 @@ export const Szene4: React.FC = () => {
|
||||||
) : (
|
) : (
|
||||||
<Figur
|
<Figur
|
||||||
pose={noaPose}
|
pose={noaPose}
|
||||||
x={noaX + (inHocke ? schieben * 10 : 0)}
|
x={noaX}
|
||||||
y={BODEN}
|
y={BODEN}
|
||||||
stauchY={atmen(f, 2) * hockeStauch * (inHocke ? 1 - 0.03 * beugen : 1)}
|
stauchY={atmen(f, 2) * hockeStauch * (inHocke ? 1 - 0.03 * beugen : 1)}
|
||||||
drehung={inHocke ? beugen * 3 + schieben * 2 : 0}
|
drehung={inHocke ? beugen * 3 : 0}
|
||||||
blende={HOCKE_BLENDE}
|
blende={HOCKE_BLENDE}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue