Schattenspiel: Mitmach-Karte mit gezeichneter Hand (wie im Zähllied) für Hase und Igel; Hand nach baukasten/hand.tsx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f303ec8d7a
commit
c937844f94
3 changed files with 85 additions and 41 deletions
48
remotion/src/baukasten/hand.tsx
Normal file
48
remotion/src/baukasten/hand.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import React from 'react';
|
||||
|
||||
// Gezeichnete Hand (Bilderbuchstil) für Mitmach-Karten: Zählen mit den Fingern (Lied 1),
|
||||
// Hand-Schatten (Folge 8). `hoch` sagt je Finger (Daumen zuerst), ob er gestreckt ist;
|
||||
// `neu` = Index des Fingers, der gerade hochschnellt, `wachsen` 0–1 dessen Fortschritt;
|
||||
// `gespreizt` fächert die gestreckten Finger auf (Igel-Stacheln).
|
||||
const HAUT = '#f4cfa6';
|
||||
const KONTUR = '#b9825a';
|
||||
const FINGER: {x: number; b: number; l: number; dreh: number}[] = [
|
||||
{x: 22, b: 24, l: 62, dreh: -48}, // Daumen
|
||||
{x: 48, b: 22, l: 84, dreh: -6},
|
||||
{x: 74, b: 22, l: 92, dreh: 0},
|
||||
{x: 100, b: 22, l: 84, dreh: 5},
|
||||
{x: 124, b: 20, l: 66, dreh: 12},
|
||||
];
|
||||
const SPREIZ = [-10, -16, -2, 12, 22];
|
||||
|
||||
export const Hand: React.FC<{hoch: boolean[]; neu?: number; wachsen?: number; spiegeln?: boolean; gespreizt?: boolean}> = ({hoch, neu = -1, wachsen = 1, spiegeln = false, gespreizt = false}) => (
|
||||
<svg width={170} height={230} viewBox="0 0 160 220" style={{transform: spiegeln ? 'scaleX(-1)' : undefined, overflow: 'visible'}}>
|
||||
{FINGER.map((fi, k) => {
|
||||
const l = hoch[k] ? (k === neu ? 18 + (fi.l - 18) * wachsen : fi.l) : 18;
|
||||
const fussY = k === 0 ? 150 : 112;
|
||||
const dreh = fi.dreh + (gespreizt && hoch[k] ? SPREIZ[k] : 0);
|
||||
return (
|
||||
<rect
|
||||
key={k}
|
||||
x={fi.x - fi.b / 2 + 6}
|
||||
y={fussY - l}
|
||||
width={fi.b}
|
||||
height={l + 20}
|
||||
rx={fi.b / 2}
|
||||
fill={HAUT}
|
||||
stroke={KONTUR}
|
||||
strokeWidth={4}
|
||||
transform={`rotate(${dreh} ${fi.x + 6} ${fussY + 10})`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<rect x={30} y={100} width={112} height={100} rx={40} fill={HAUT} stroke={KONTUR} strokeWidth={4} />
|
||||
{/* eingeklappte Finger als kleine Knöchel */}
|
||||
{FINGER.slice(1).map((fi, k) => (!hoch[k + 1] ? <path key={k} d={`M ${fi.x - 4} 118 q 11 10 22 0`} stroke={KONTUR} strokeWidth={3} fill="none" opacity={0.7} /> : null))}
|
||||
</svg>
|
||||
);
|
||||
|
||||
// Zählen: die ersten `finger` Finger gestreckt (Daumen = 1, wie in Deutschland üblich)
|
||||
export const ZaehlHand: React.FC<{finger: number; neu: number; spiegeln?: boolean}> = ({finger, neu, spiegeln}) => (
|
||||
<Hand hoch={[0, 1, 2, 3, 4].map((k) => k < finger)} neu={finger - 1} wachsen={neu} spiegeln={spiegeln} />
|
||||
);
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import React from 'react';
|
||||
import {interpolate, useCurrentFrame} from 'remotion';
|
||||
import {Hand} from '../baukasten/hand';
|
||||
import {Blende, kamFahrt, punkt} from '../baukasten/helfer';
|
||||
import {SCHRIFT} from '../baukasten/untertitel';
|
||||
import {BODEN} from '../baukasten/orte';
|
||||
import {POSEN_SKALA} from '../baukasten/figur';
|
||||
import {Untertitel} from '../baukasten/untertitel';
|
||||
|
|
@ -9,7 +11,8 @@ import {HandSchatten, NoasHand} from './teile';
|
|||
import {PLATZ, Wandszene} from './wand';
|
||||
|
||||
// Szene 7: Schattenspiel. Noa macht mit der Hand vor der Laterne einen Hasen, dann einen Igel.
|
||||
// Die Kinder machen mit (Pausen). Lulu streckt den Hals lang, ihr Schatten reicht bis zum Dach.
|
||||
// Die Kinder machen mit (Pausen): Solange der Erzähler erklärt, zeigt oben links eine Karte die Hand
|
||||
// (gezeichnet wie beim Zähllied), welche Finger hoch müssen. Lulu streckt den Hals lang.
|
||||
|
||||
export const S7 = plane('s7', [
|
||||
{id: 'bild0', dauer: 1.2},
|
||||
|
|
@ -32,6 +35,34 @@ const HAND = {x: 955, y: 770};
|
|||
const HAND_S = 0.3;
|
||||
const K = 3; // Hand nah am Licht → großer Schatten
|
||||
|
||||
// Mitmach-Karte oben links (oben rechts erscheint in der Pause das „?“)
|
||||
const HandKarte: React.FC<{art: 'hase' | 'igel'; von: number; bis: number}> = ({art, von, bis}) => {
|
||||
const f = useCurrentFrame();
|
||||
const auf = interpolate(f, [von, von + 10, bis - 8, bis], [0, 1, 1, 0], {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'});
|
||||
if (auf <= 0) return null;
|
||||
const wackeln = Math.sin(f * 0.18) * 3;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: 56,
|
||||
top: 44,
|
||||
padding: '18px 26px 10px',
|
||||
borderRadius: 36,
|
||||
background: 'rgba(251,244,228,0.94)',
|
||||
border: '8px solid #3f5a8a',
|
||||
boxShadow: '0 8px 26px rgba(60,40,20,0.22)',
|
||||
fontFamily: SCHRIFT,
|
||||
opacity: auf,
|
||||
transform: `scale(${0.85 + 0.15 * auf}) rotate(${wackeln}deg)`,
|
||||
transformOrigin: '0 0',
|
||||
}}
|
||||
>
|
||||
<Hand hoch={art === 'hase' ? [false, true, true, false, false] : [true, true, true, true, true]} gespreizt />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Szene7: React.FC = () => {
|
||||
const f = useCurrentFrame();
|
||||
const {z, dauer} = S7;
|
||||
|
|
@ -71,6 +102,8 @@ export const Szene7: React.FC = () => {
|
|||
</>
|
||||
}
|
||||
/>
|
||||
<HandKarte art="hase" von={z.e1.start} bis={z.e1.frei} />
|
||||
<HandKarte art="igel" von={z.e3.start} bis={z.e3.frei} />
|
||||
<Untertitel zeilen={S7.liste} />
|
||||
<Blende dauer={dauer} rein={6} raus={14} />
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import {AbsoluteFill, Audio, Sequence, interpolate, spring, staticFile, useCurrentFrame} from 'remotion';
|
||||
import {INTRO_OPTIONEN, Intro, OUTRO, Outro} from '../../baukasten/buch';
|
||||
import {ClipFigur, Figur, Kamera, type Posenfolge} from '../../baukasten/figur';
|
||||
import {ZaehlHand} from '../../baukasten/hand';
|
||||
import {Blende, LULU_KOPF, Vignette, huepfer, kamFahrt, luluMaulC9, punkt} from '../../baukasten/helfer';
|
||||
import {Apfel, Funkeln, Ruf} from '../../baukasten/natur';
|
||||
import {BODEN, Ort} from '../../baukasten/orte';
|
||||
|
|
@ -179,44 +180,6 @@ const Liedapfel: React.FC<{i: number; f: number}> = ({i, f}) => {
|
|||
);
|
||||
};
|
||||
|
||||
// Hand mit hochgestreckten Fingern (Daumen zählt als 1)
|
||||
const HAUT = '#f4cfa6';
|
||||
const KONTUR = '#b9825a';
|
||||
const FINGER: {x: number; b: number; l: number; dreh: number}[] = [
|
||||
{x: 22, b: 24, l: 62, dreh: -48}, // Daumen
|
||||
{x: 48, b: 22, l: 84, dreh: -6},
|
||||
{x: 74, b: 22, l: 92, dreh: 0},
|
||||
{x: 100, b: 22, l: 84, dreh: 5},
|
||||
{x: 124, b: 20, l: 66, dreh: 12},
|
||||
];
|
||||
const Hand: React.FC<{finger: number; neu: number; spiegeln?: boolean}> = ({finger, neu, spiegeln = false}) => (
|
||||
<svg width={170} height={230} viewBox="0 0 160 220" style={{transform: spiegeln ? 'scaleX(-1)' : undefined, overflow: 'visible'}}>
|
||||
{FINGER.map((fi, k) => {
|
||||
const hoch = k < finger;
|
||||
// der zuletzt dazugekommene Finger schnellt hoch
|
||||
const l = hoch ? (k === finger - 1 ? 18 + (fi.l - 18) * neu : fi.l) : 18;
|
||||
const fussY = k === 0 ? 150 : 112;
|
||||
return (
|
||||
<rect
|
||||
key={k}
|
||||
x={fi.x - fi.b / 2 + 6}
|
||||
y={fussY - l}
|
||||
width={fi.b}
|
||||
height={l + 20}
|
||||
rx={fi.b / 2}
|
||||
fill={HAUT}
|
||||
stroke={KONTUR}
|
||||
strokeWidth={4}
|
||||
transform={`rotate(${fi.dreh} ${fi.x + 6} ${fussY + 10})`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<rect x={30} y={100} width={112} height={100} rx={40} fill={HAUT} stroke={KONTUR} strokeWidth={4} />
|
||||
{/* eingeklappte Finger als kleine Knöchel */}
|
||||
{FINGER.slice(1).map((fi, k) => (k + 1 >= finger ? <path key={k} d={`M ${fi.x - 4} 118 q 11 10 22 0`} stroke={KONTUR} strokeWidth={3} fill="none" opacity={0.7} /> : null))}
|
||||
</svg>
|
||||
);
|
||||
|
||||
// Zahl und Hände oben rechts
|
||||
type Anzeige = {n: number | '?'; seit: number; deck: number};
|
||||
const anzeige = (f: number): Anzeige | null => {
|
||||
|
|
@ -259,8 +222,8 @@ const Zahltafel: React.FC = () => {
|
|||
<>
|
||||
<div style={{fontSize: 190, lineHeight: 1, color: '#c8502c', minWidth: 150, textAlign: 'center', transform: `scale(${0.6 + 0.4 * pop})`}}>{n}</div>
|
||||
<div style={{display: 'flex', gap: 4, alignItems: 'flex-end'}}>
|
||||
<Hand finger={Math.min(n, 5)} neu={n <= 5 ? neu : 1} />
|
||||
{n > 5 && <Hand finger={n - 5} neu={neu} spiegeln />}
|
||||
<ZaehlHand finger={Math.min(n, 5)} neu={n <= 5 ? neu : 1} />
|
||||
{n > 5 && <ZaehlHand finger={n - 5} neu={neu} spiegeln />}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue