nezuhub/simple / scenes /Loop.tsx
nezuhub's picture
download
raw
7.21 kB
import React from 'react';
import { AbsoluteFill } from 'remotion';
import { C, DISPLAY, MONO } from '../theme';
import { backOut, easeOut, glow, lerp, prog } from '../lib/anim';
const polar = (cx: number, cy: number, r: number, deg: number) => ({
x: cx + r * Math.cos((deg * Math.PI) / 180),
y: cy + r * Math.sin((deg * Math.PI) / 180),
});
const arc = (cx: number, cy: number, r: number, a0: number, a1: number) => {
const s = polar(cx, cy, r, a0);
const e = polar(cx, cy, r, a1);
const large = a1 - a0 > 180 ? 1 : 0;
return `M ${s.x} ${s.y} A ${r} ${r} 0 ${large} 1 ${e.x} ${e.y}`;
};
const Equation: React.FC<{ f: number }> = ({ f }) => {
const parts = ['7641', '−', '1467', '=', '6174'];
return (
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 18, fontFamily: MONO, fontWeight: 700 }}>
{parts.map((p, i) => {
const o = easeOut(prog(f, 46 + i * 11, 58 + i * 11));
return (
<span
key={i}
style={{
fontSize: p === '6174' ? 62 : 52,
color: p === '6174' ? C.gold : p === '−' || p === '=' ? C.dim : C.ink,
letterSpacing: '0.05em',
opacity: o,
transform: `translateY(${(1 - o) * 14}px)`,
display: 'inline-block',
textShadow: p === '6174' ? glow(C.gold, 22, 0.6) : undefined,
}}
>
{p}
</span>
);
})}
</div>
);
};
export const Loop: React.FC<{ f: number; dur: number }> = ({ f }) => {
const cta = easeOut(prog(f, 132, 158));
const topOut = 1 - prog(f, 126, 148);
const draw = easeOut(prog(f, 8, 46));
const R = 246;
const d = arc(540, 560, R, -150, 150);
const len = (Math.PI * R * 300) / 180;
return (
<AbsoluteFill>
<div style={{ position: 'absolute', top: 190, left: 90, right: 90, display: 'flex', justifyContent: 'space-between', alignItems: 'center', opacity: topOut }}>
<div style={{ fontFamily: MONO, fontSize: 22, letterSpacing: '0.4em', color: C.cyan }}>THE TRAP</div>
<div style={{ fontFamily: MONO, fontSize: 20, letterSpacing: '0.2em', color: C.dim }}>04 / 04</div>
</div>
<div style={{ position: 'absolute', top: 234, left: 90, width: 900, height: 1, background: 'linear-gradient(90deg, rgba(89,227,255,0.5), rgba(89,227,255,0))', opacity: topOut }} />
{/* the loop */}
<div style={{ opacity: topOut }}>
<AbsoluteFill style={{ alignItems: 'center' }}>
<div
style={{
position: 'absolute',
top: 360,
fontFamily: DISPLAY,
fontWeight: 700,
fontSize: 196,
letterSpacing: '0.04em',
color: C.gold,
textShadow: glow(C.gold, 46, 0.7),
transform: `scale(${1 + 0.02 * Math.sin(f * 0.14)})`,
}}
>
6174
</div>
</AbsoluteFill>
<svg width={1080} height={1920} viewBox="0 0 1080 1920" style={{ position: 'absolute' }}>
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M 0 0 L 8 3 L 0 6 z" fill={C.gold} />
</marker>
</defs>
<path
d={d}
fill="none"
stroke={C.gold}
strokeOpacity={0.22}
strokeWidth={2}
strokeDasharray="2 10"
transform={`rotate(${f * 0.3} 540 560)`}
/>
<path
d={d}
fill="none"
stroke={C.gold}
strokeWidth={3.4}
strokeLinecap="round"
markerEnd="url(#arrow)"
strokeDasharray={`${len} ${len}`}
strokeDashoffset={len * (1 - draw)}
transform={`rotate(${f * 0.3} 540 560)`}
opacity={0.9}
/>
{[0, 1, 2].map((i) => {
const a = f * 1.1 + i * 120 - 150;
const pt = polar(540, 560, R, a);
return <circle key={i} cx={pt.x} cy={pt.y} r={3.4} fill={i === 0 ? '#FFF3C9' : C.gold} opacity={0.8} />;
})}
</svg>
<div style={{ position: 'absolute', top: 862, left: 0, right: 0 }}>
<Equation f={f} />
</div>
<div
style={{
position: 'absolute',
top: 992,
left: 0,
right: 0,
textAlign: 'center',
fontFamily: DISPLAY,
fontWeight: 700,
fontSize: 46,
letterSpacing: '0.55em',
color: C.gold,
opacity: easeOut(prog(f, 100, 124)),
textShadow: glow(C.gold, 18, 0.4),
}}
>
FOREVER
</div>
</div>
{/* CTA */}
<AbsoluteFill style={{ opacity: cta, transform: `translateY(${(1 - cta) * 40}px)` }}>
<div
style={{
position: 'absolute',
top: 430,
left: 0,
right: 0,
textAlign: 'center',
fontFamily: DISPLAY,
fontWeight: 700,
fontSize: 300,
color: C.gold,
opacity: 0.05,
letterSpacing: '-0.02em',
}}
>
6174
</div>
<div style={{ position: 'absolute', top: 540, left: 60, right: 60, textAlign: 'center' }}>
<div style={{ fontFamily: MONO, fontSize: 22, letterSpacing: '0.4em', color: C.cyan, marginBottom: 30 }}>YOUR TURN</div>
<div style={{ fontFamily: DISPLAY, fontWeight: 700, fontSize: 92, lineHeight: 1.04, letterSpacing: '-0.035em', color: C.ink }}>
HOW MANY STEPS
</div>
<div style={{ fontFamily: DISPLAY, fontWeight: 700, fontSize: 92, lineHeight: 1.04, letterSpacing: '-0.035em', color: C.ink, marginBottom: 54 }}>
DID <span style={{ color: C.gold }}>YOURS</span> TAKE?
</div>
<div
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 14,
background: C.gold,
color: '#120C02',
fontFamily: DISPLAY,
fontWeight: 700,
fontSize: 40,
letterSpacing: '0.12em',
padding: '20px 42px',
borderRadius: 999,
transform: `scale(${1 + 0.025 * Math.sin(f * 0.18)})`,
boxShadow: `0 0 54px rgba(255,201,74,0.4)`,
}}
>
COMMENT IT
<span style={{ fontSize: 34 }}>↓</span>
</div>
</div>
<div
style={{
position: 'absolute',
top: 1120,
left: 0,
right: 0,
textAlign: 'center',
fontFamily: MONO,
fontSize: 20,
letterSpacing: '0.32em',
color: C.dim,
opacity: backOut(prog(f, 200, 222)),
}}
>
KAPREKAR&apos;S CONSTANT · 6174
</div>
</AbsoluteFill>
{f >= 316 ? <AbsoluteFill style={{ background: '#000', opacity: prog(f, 316, 330) }} /> : null}
</AbsoluteFill>
);
};

Xet Storage Details

Size:
7.21 kB
·
Xet hash:
307d8d0ea5d0698f32b6f3b97a05846de2e9f62539a7938e66c9cf6c5f3a2517

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.