121 lines
3.3 KiB
TypeScript
121 lines
3.3 KiB
TypeScript
/**
|
|
* Abstract editorial hero — a custom illustration (inline SVG, no asset).
|
|
* • MCM → a constellation of interconnected nodes (vermillion).
|
|
* • QUIC → flowing, multiplexed streams (cobalt), animated dash flow.
|
|
* Animations are pure CSS (tailwind keyframes: node-pulse, stream-dash).
|
|
*
|
|
* CUSTOMIZATION HOOK — palette is inherited from CSS vars; geometry below.
|
|
*/
|
|
export default function HeroComposition({
|
|
className = "",
|
|
}: {
|
|
className?: string;
|
|
}) {
|
|
// MCM node coordinates (interconnected mesh, upper-left field).
|
|
const nodes = [
|
|
{ x: 70, y: 90 },
|
|
{ x: 160, y: 60 },
|
|
{ x: 130, y: 170 },
|
|
{ x: 230, y: 130 },
|
|
{ x: 60, y: 210 },
|
|
{ x: 210, y: 240 },
|
|
];
|
|
// Mesh edges between nodes (index pairs).
|
|
const edges: [number, number][] = [
|
|
[0, 1],
|
|
[0, 2],
|
|
[1, 3],
|
|
[2, 3],
|
|
[2, 4],
|
|
[3, 5],
|
|
[2, 5],
|
|
[4, 5],
|
|
];
|
|
|
|
return (
|
|
<svg
|
|
viewBox="0 0 380 380"
|
|
role="img"
|
|
aria-label="MCM 상호운용 노드와 QUIC 멀티스트림을 형상화한 추상 일러스트레이션"
|
|
className={className}
|
|
>
|
|
{/* Frame */}
|
|
<rect
|
|
x="6"
|
|
y="6"
|
|
width="368"
|
|
height="368"
|
|
fill="none"
|
|
stroke="#0A0A0A"
|
|
strokeWidth="1.5"
|
|
/>
|
|
|
|
{/* ---- QUIC: flowing multiplexed streams (cobalt) ---- */}
|
|
<g stroke="#1B3A8A" fill="none" strokeWidth="2.5" strokeLinecap="round">
|
|
{[0, 1, 2, 3].map((i) => {
|
|
const y = 250 + i * 30;
|
|
return (
|
|
<path
|
|
key={i}
|
|
d={`M 30 ${y} C 140 ${y - 40}, 240 ${y + 40}, 360 ${y - 20}`}
|
|
strokeDasharray="10 14"
|
|
className="animate-stream-dash"
|
|
style={{ animationDelay: `${i * 0.6}s`, opacity: 0.85 }}
|
|
/>
|
|
);
|
|
})}
|
|
</g>
|
|
|
|
{/* ---- MCM: interconnected node mesh (vermillion) ---- */}
|
|
<g stroke="#D9342B" strokeWidth="1.5">
|
|
{edges.map(([a, b], i) => (
|
|
<line
|
|
key={i}
|
|
x1={nodes[a].x}
|
|
y1={nodes[a].y}
|
|
x2={nodes[b].x}
|
|
y2={nodes[b].y}
|
|
opacity="0.55"
|
|
/>
|
|
))}
|
|
</g>
|
|
<g fill="#D9342B">
|
|
{nodes.map((n, i) => (
|
|
<circle
|
|
key={i}
|
|
cx={n.x}
|
|
cy={n.y}
|
|
r={i % 2 === 0 ? 9 : 6}
|
|
className="animate-node-pulse"
|
|
style={{
|
|
animationDelay: `${i * 0.5}s`,
|
|
transformBox: "fill-box",
|
|
transformOrigin: "center",
|
|
}}
|
|
/>
|
|
))}
|
|
</g>
|
|
|
|
{/* Annotations — placed in the top corners (y=24), clear of the
|
|
MCM node mesh (y=60..240) and the QUIC stream curves (y≥250 with
|
|
control points reaching y+40=380). See LAYOUT_AUDIT #3 and
|
|
REVIEW §3 "P1 #3" — keeping them at y=24 (mirror corners) preserves
|
|
a symmetric layout that the original LAYOUT_AUDIT mirror decided on. */}
|
|
<text x="20" y="24" fill="#0A0A0A" fontSize="11" fontWeight="600" letterSpacing="2">
|
|
MCM · MESH
|
|
</text>
|
|
<text
|
|
x="360"
|
|
y="24"
|
|
textAnchor="end"
|
|
fill="#0A0A0A"
|
|
fontSize="11"
|
|
fontWeight="600"
|
|
letterSpacing="2"
|
|
>
|
|
QUIC · STREAMS
|
|
</text>
|
|
</svg>
|
|
);
|
|
}
|