// video-scenes.jsx — kinetic typography scenes for "Für Branding mit Emotionen"
// Uses engine globals: useTime, Easing, interpolate, animate, clamp.
const { useTime: vUseTime, Easing: E, interpolate: vInterp, animate: vAnim, clamp: vClamp } = window;
const VC = {
bg: '#1A1A1A', bg2: '#212121',
accent: '#C0392B', accent2: '#D35400',
text: '#ECECEC', dim: '#8C8C8C', faint: '#5A5A5A',
};
const DISP = "'Barlow Condensed', sans-serif";
const SEMI = "'Barlow Semi Condensed', sans-serif";
const BODY = "'Barlow', sans-serif";
// ── Scene wrapper: opacity envelope + centered full frame ───────────────────
function SceneWrap({ start, end, fadeIn = 0.5, fadeOut = 0.5, bg, children }) {
const t = vUseTime();
if (t < start - 0.0001 || t > end + 0.0001) return null;
const lt = t - start;
const dur = end - start;
let op = 1;
if (fadeIn > 0 && lt < fadeIn) op = E.easeInOutSine(vClamp(lt / fadeIn, 0, 1));
else if (fadeOut > 0 && lt > dur - fadeOut) op = E.easeInOutSine(vClamp((dur - lt) / fadeOut, 0, 1));
return (
{children(lt, dur, t)}
);
}
const Kicker = ({ text, color = VC.dim, size = 46, ...rest }) => (
{text}
);
// ── SCENE 1 — MANCHMAL LAUT. (loud: slam + shake + sound blasts) ────────────
function SceneLaut({ start, end }) {
return (
{(lt, dur, t) => {
// entry slam
const scale = vAnim({ from: 1.6, to: 1, start: 0, end: 0.55, ease: E.easeOutBack })(lt);
const introOp = vClamp(lt / 0.18, 0, 1);
// decaying vibration
const decay = vClamp(1 - (lt - 0.55) / 2.6, 0, 1);
const shakeX = lt > 0.55 ? Math.sin(t * 58) * 5 * decay : 0;
const shakeY = lt > 0.55 ? Math.cos(t * 71) * 4 * decay : 0;
// flash
const flash = vClamp(1 - lt / 0.3, 0, 1) * 0.55;
const rings = [0, 1, 2, 3, 4];
return (
{/* sound blast rings */}
{rings.map((i) => {
const phase = ((lt * 0.85) + i * 0.26) % 1;
const d = phase * 1700;
const o = (1 - phase) * 0.4 * vClamp(lt / 0.4, 0, 1);
return
;
})}
);
}}
);
}
// ── SCENE 2 — MANCHMAL LEISE. (quiet: soft blur-in, drift, hush) ────────────
function SceneLeise({ start, end }) {
return (
{(lt, dur, t) => {
const blur = vClamp(10 - lt * 9, 0, 10);
const drift = -lt * 6; // slow upward drift
const track = vInterp([0, 1.2], [0.34, 0.5], E.easeOutCubic)(lt);
const lineW = vAnim({ from: 0, to: 360, start: 0.3, end: 1.6, ease: E.easeOutCubic })(lt);
return (
);
}}
);
}
// ── SCENE 3 — MANCHMAL KRAFTVOLL. (powerful: drive-in + speed lines) ────────
function SceneKraftvoll({ start, end }) {
return (
{(lt, dur, t) => {
const x = vAnim({ from: -620, to: 0, start: 0, end: 0.6, ease: E.easeOutBack })(lt);
const zoom = vInterp([0.6, dur], [1, 1.04], E.easeOutSine)(lt);
const op = vClamp(lt / 0.15, 0, 1);
const lines = [0, 1, 2, 3, 4, 5, 6, 7];
return (
{/* diagonal speed lines */}
{lines.map((i) => {
const phase = ((t * 0.55) + i * 0.135) % 1;
const lx = -400 + phase * 3000;
const o = Math.sin(phase * Math.PI) * 0.5;
const len = 180 + (i % 3) * 160;
return
;
})}
);
}}
);
}
// ── SCENE 4 — MANCHMAL RUHIGER. (calm: slow waves, settle) ──────────────────
function CalmWaves({ t }) {
const W = 1920, H = 1080, mid = 640;
const mk = (amp, speed, phase, stroke, op, yoff) => {
let d = `M 0 ${mid + yoff}`;
for (let x = 0; x <= W; x += 40) {
const y = mid + yoff + Math.sin((x / W) * Math.PI * 3 + t * speed + phase) * amp;
d += ` L ${x} ${y}`;
}
return ;
};
return (
);
}
function SceneRuhiger({ start, end }) {
return (
{(lt, dur, t) => {
const track = vInterp([0, 1.5], [0.28, 0.4], E.easeOutCubic)(lt);
const rise = vAnim({ from: 22, to: 0, start: 0, end: 1.4, ease: E.easeOutCubic })(lt);
return (
);
}}
);
}
// ── Tacho mark (bridge to website) ──────────────────────────────────────────
const polar = (cx, cy, r, deg) => { const a = (deg - 90) * Math.PI / 180; return [cx + r * Math.cos(a), cy + r * Math.sin(a)]; };
function arcPath(cx, cy, r, d0, d1) {
const [x0, y0] = polar(cx, cy, r, d0), [x1, y1] = polar(cx, cy, r, d1);
const large = (d1 - d0) > 180 ? 1 : 0;
return `M ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1}`;
}
const tachoAngle = (v) => 225 + (v / 8000) * 270;
function TachoMark({ prog }) {
const cx = 130, cy = 128, R = 100;
const ang = 225 + (tachoAngle(7900) - 225) * E.easeOutCubic(prog);
const ticks = [];
for (let v = 0; v <= 8000; v += 1000) {
const deg = tachoAngle(v); const red = v >= 6500;
const [ox, oy] = polar(cx, cy, R, deg); const [ix, iy] = polar(cx, cy, R - 16, deg);
ticks.push();
}
return (
);
}
// ── SCENE 5 — OUTRO (tagline → brand signature) ─────────────────────────────
function SceneOutro({ start, end }) {
return (
{(lt, dur, t) => {
// Beat A: tagline (0 → 2.7), Beat B: signature (2.6 → end)
const aOut = vClamp(1 - (lt - 2.4) / 0.5, 0, 1);
const aIn = vClamp(lt / 0.5, 0, 1);
const aOp = E.easeInOutSine(Math.min(aIn, aOut));
const bIn = vClamp((lt - 2.6) / 0.6, 0, 1);
const bOp = E.easeOutCubic(bIn);
const bRise = (1 - bOp) * 26;
const needleProg = vClamp((lt - 2.9) / 1.5, 0, 1);
return (
{/* racing stripe */}
{/* Beat A — tagline */}
Für Branding
mit Emotionen.
{/* Beat B — signature */}
Mark Schönholzer
Senior Marketing Leader
);
}}
);
}
Object.assign(window, { SceneLaut, SceneLeise, SceneKraftvoll, SceneRuhiger, SceneOutro, VC });