Files
teknav-bak/app/teknav-diagrams.jsx
T
arsam efc73230ca Import source: app/teknav-diagrams
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
2026-09-18 23:26:18 +03:30

1182 lines
56 KiB
React
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect, useRef } from 'react';
import * as THREE from 'three';
function NeuralNetworkDiagram({ width = 420, height = 280 }) {
const [hovered, setHovered] = useState(null);
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 80); return () => clearInterval(id); }, []);
const layers = [
{ x: 60, nodes: [80, 130, 180, 230], label: 'لایه ورودی' },
{ x: 160, nodes: [100, 155, 210], label: 'لایه پنهان ۱' },
{ x: 260, nodes: [110, 165, 220], label: 'لایه توجه' },
{ x: 360, nodes: [140, 195], label: 'خروجی مدل' },
];
const pulses = [];
for (let li = 0; li < layers.length - 1; li++) {
const from = layers[li], to = layers[li + 1];
from.nodes.forEach((fy, fi) => {
to.nodes.forEach((ty, ti) => {
const phase = (tick + li * 7 + fi * 3 + ti * 5) % 40;
if (phase < 20) pulses.push({ x: from.x + (to.x - from.x) * phase / 20, y: fy + (ty - fy) * phase / 20 });
});
});
}
const nodeColors = ['#0F6B73', '#D49A2A', '#C76D4A', '#2F8F6B'];
return (
<svg width="100%" viewBox={`0 0 ${width} ${height}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
{layers.map((layer, li) =>
layers[li + 1] && layer.nodes.map((fy, fi) =>
layers[li + 1].nodes.map((ty, ti) => (
<line key={`${li}-${fi}-${ti}`} x1={layer.x} y1={fy} x2={layers[li+1].x} y2={ty}
stroke="#E4DDD2" strokeWidth="1" opacity="0.6" />
))
)
)}
{pulses.map((p, i) => (
<circle key={i} cx={p.x} cy={p.y} r="3" fill="#D49A2A" opacity="0.75" />
))}
{layers.map((layer, li) =>
layer.nodes.map((y, ni) => (
<g key={`n-${li}-${ni}`} onMouseEnter={() => setHovered(`${li}-${ni}`)} onMouseLeave={() => setHovered(null)} style={{ cursor: 'pointer' }}>
<circle cx={layer.x} cy={y} r={hovered === `${li}-${ni}` ? 13 : 10} fill={nodeColors[li]} opacity={hovered === `${li}-${ni}` ? 1 : 0.85}
style={{ transition: 'r 0.15s' }} />
{hovered === `${li}-${ni}` && (
<g>
<rect x={layer.x - 60} y={y - 30} width="120" height="22" rx="4" fill="#20343A" opacity="0.9" />
<text x={layer.x} y={y - 15} textAnchor="middle" fill="#FAF7F0" fontSize="10">{layer.label}</text>
</g>
)}
</g>
))
)}
{layers.map((layer, li) => (
<text key={`l-${li}`} x={layer.x} y={height - 8} textAnchor="middle" fill="#5F6B6D" fontSize="9">{layer.label}</text>
))}
</svg>
);
}
function DataPipelineDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
const [hovered, setHovered] = useState(null);
useEffect(() => { const id = setInterval(() => setTick(t => (t + 1) % 100), 60); return () => clearInterval(id); }, []);
const steps = [
{ id: 'raw', label: 'داده خام', icon: '⬡', color: '#5F6B6D', desc: 'جمع‌آوری از منابع مختلف' },
{ id: 'clean', label: 'پاک‌سازی', icon: '◈', color: '#D49A2A', desc: 'حذف تکراری و نویز' },
{ id: 'label', label: 'برچسب‌گذاری', icon: '◉', color: '#C76D4A', desc: 'دسته‌بندی و تعریف' },
{ id: 'feature', label: 'ویژگی‌سازی', icon: '⬟', color: '#0F6B73', desc: 'استخراج ویژگی' },
{ id: 'train', label: 'آموزش مدل', icon: '◈', color: '#2F8F6B', desc: 'یادگیری از داده' },
{ id: 'eval', label: 'ارزیابی', icon: '◉', color: '#D49A2A', desc: 'سنجش عملکرد' },
{ id: 'output', label: 'خروجی', icon: '★', color: '#0F6B73', desc: 'مدل آماده' },
];
const W = compact ? 480 : 700, H = compact ? 140 : 180;
const stepW = W / steps.length;
return (
<svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ fontFamily: 'Vazirmatn, sans-serif', overflow: 'visible' }}>
<line x1={stepW * 0.5} y1={H / 2} x2={W - stepW * 0.5} y2={H / 2} stroke="#E4DDD2" strokeWidth="2" />
{[0, 25, 50, 75].map(offset => {
const pos = ((tick + offset) % 100) / 100;
const x = stepW * 0.5 + pos * (W - stepW);
return <circle key={offset} cx={x} cy={H / 2} r="4" fill="#D49A2A" opacity={0.8} />;
})}
{steps.map((step, i) => {
const cx = stepW * (i + 0.5);
const isHov = hovered === step.id;
return (
<g key={step.id} onMouseEnter={() => setHovered(step.id)} onMouseLeave={() => setHovered(null)} style={{ cursor: 'pointer' }}>
<circle cx={cx} cy={H / 2} r={isHov ? 26 : 22} fill={step.color} opacity={isHov ? 1 : 0.85} style={{ transition: 'all 0.2s' }} />
<text x={cx} y={H / 2 + 5} textAnchor="middle" fill="#fff" fontSize={compact ? 11 : 13} fontWeight="700">{i + 1}</text>
<text x={cx} y={H / 2 + (compact ? 36 : 42)} textAnchor="middle" fill="#263238" fontSize={compact ? 9 : 10}>{step.label}</text>
{isHov && (
<g>
<rect x={cx - 55} y={H / 2 - 52} width="110" height="22" rx="4" fill="#20343A" opacity="0.92" />
<text x={cx} y={H / 2 - 37} textAnchor="middle" fill="#FAF7F0" fontSize="9">{step.desc}</text>
</g>
)}
</g>
);
})}
</svg>
);
}
function CyberSecurityDiagram() {
const [hovered, setHovered] = useState(null);
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 100); return () => clearInterval(id); }, []);
const cx = 200, cy = 150, r = 90;
const threats = [
{ angle: 0, label: 'فیشینگ', color: '#C94C4C' },
{ angle: 60, label: 'حمله زنجیره تأمین', color: '#D08A22' },
{ angle: 120, label: 'آسیب‌پذیری کتابخانه', color: '#C76D4A' },
{ angle: 180, label: 'دسترسی غیرمجاز', color: '#C94C4C' },
{ angle: 240, label: 'باج‌افزار', color: '#D08A22' },
{ angle: 300, label: 'حمله DDoS', color: '#C76D4A' },
];
return (
<svg width="100%" viewBox="0 0 400 300" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<circle cx={cx} cy={cy} r={55} fill="none" stroke="#2F8F6B" strokeWidth="2.5" strokeDasharray="8 4"
style={{ animation: 'spin 20s linear infinite', transformOrigin: `${cx}px ${cy}px` }} />
<rect x={cx - 22} y={cy - 28} width="44" height="56" rx="6" fill="#20343A" />
<rect x={cx - 16} y={cy - 22} width="32" height="6" rx="2" fill="#0F6B73" />
<rect x={cx - 16} y={cy - 12} width="32" height="6" rx="2" fill="#0F6B73" />
<rect x={cx - 16} y={cy - 2} width="32" height="6" rx="2" fill="#0F6B73" />
<circle cx={cx + 12} cy={cy + 16} r="3" fill="#2F8F6B" />
<text x={cx} y={cy + 42} textAnchor="middle" fill="#5F6B6D" fontSize="9">سرور مرکزی</text>
{threats.map((t, i) => {
const rad = (t.angle * Math.PI) / 180;
const tx = cx + Math.cos(rad) * r;
const ty = cy + Math.sin(rad) * r;
const lx = cx + Math.cos(rad) * (r + 38);
const ly = cy + Math.sin(rad) * (r + 38);
const isH = hovered === i;
const pulse = (tick + i * 6) % 30 < 15;
return (
<g key={i} onMouseEnter={() => setHovered(i)} onMouseLeave={() => setHovered(null)} style={{ cursor: 'pointer' }}>
<line x1={cx + Math.cos(rad) * 55} y1={cy + Math.sin(rad) * 55} x2={tx} y2={ty}
stroke={t.color} strokeWidth={isH ? 2 : 1} strokeDasharray={pulse ? '6 3' : '3 6'} opacity={0.7} />
<circle cx={tx} cy={ty} r={isH ? 10 : 8} fill={t.color} opacity={isH ? 1 : 0.75} style={{ transition: 'all 0.15s' }} />
{isH && (
<g>
<rect x={lx - 55} y={ly - 14} width="110" height="20" rx="4" fill="#20343A" opacity="0.92" />
<text x={lx} y={ly - 1} textAnchor="middle" fill="#FAF7F0" fontSize="9">{t.label}</text>
</g>
)}
</g>
);
})}
<style>{`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}</style>
</svg>
);
}
function StartupGrowthDiagram() {
const [progress, setProgress] = useState(0);
useEffect(() => {
let v = 0;
const id = setInterval(() => { v = Math.min(v + 2, 100); setProgress(v); if (v >= 100) clearInterval(id); }, 20);
return () => clearInterval(id);
}, []);
const milestones = ['ایده', 'محصول اولیه', 'جذب کاربر', 'درآمد', 'مقیاس‌پذیری'];
const W = 400, H = 200, padX = 40, padY = 20;
const points = milestones.map((_, i) => {
const t = i / (milestones.length - 1);
return { x: padX + t * (W - padX * 2), y: H - padY - Math.pow(t, 1.8) * (H - padY * 3) };
});
const drawProgress = Math.min(progress / 100, 1);
const pathPoints = points.filter((_, i) => i / (milestones.length - 1) <= drawProgress + 0.01);
const pathD = pathPoints.length > 1
? pathPoints.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ')
: '';
return (
<svg width="100%" viewBox={`0 0 ${W} ${H + 30}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<line x1={padX} y1={H - padY} x2={W - padX} y2={H - padY} stroke="#E4DDD2" strokeWidth="1.5" />
<line x1={padX} y1={padY} x2={padX} y2={H - padY} stroke="#E4DDD2" strokeWidth="1.5" />
{pathD && <path d={pathD} fill="none" stroke="#0F6B73" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />}
{pathPoints.length > 1 && (
<path d={`${pathD} L ${pathPoints[pathPoints.length-1].x} ${H - padY} L ${pathPoints[0].x} ${H - padY} Z`}
fill="#0F6B73" opacity="0.08" />
)}
{points.map((p, i) => {
const t = i / (milestones.length - 1);
const visible = t <= drawProgress + 0.01;
return visible ? (
<g key={i}>
<circle cx={p.x} cy={p.y} r="7" fill="#D49A2A" />
<text x={p.x} y={H + 15} textAnchor="middle" fill="#5F6B6D" fontSize="9">{milestones[i]}</text>
</g>
) : null;
})}
<text x={W / 2} y={padY - 5} textAnchor="middle" fill="#263238" fontSize="10" fontWeight="600">منحنی رشد استارتاپ</text>
</svg>
);
}
function HardwareChipDiagram() {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 70); return () => clearInterval(id); }, []);
const blocks = [
{ x: 30, y: 60, w: 80, h: 40, label: 'حافظه', color: '#D49A2A' },
{ x: 160, y: 40, w: 80, h: 80, label: 'پردازنده', color: '#0F6B73' },
{ x: 290, y: 60, w: 80, h: 40, label: 'شتاب‌دهنده AI', color: '#C76D4A' },
{ x: 30, y: 150, w: 80, h: 40, label: 'گذرگاه داده', color: '#2F8F6B' },
{ x: 290, y: 150, w: 80, h: 40, label: 'کنترلر حافظه', color: '#5F6B6D' },
];
const routes = [
{ x1: 110, y1: 80, x2: 160, y2: 80 },
{ x1: 240, y1: 80, x2: 290, y2: 80 },
{ x1: 110, y1: 170, x2: 160, y2: 120 },
{ x1: 240, y1: 100, x2: 290, y2: 170 },
{ x1: 200, y1: 120, x2: 200, y2: 170 },
];
return (
<svg width="100%" viewBox="0 0 400 220" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="10" y="20" width="380" height="190" rx="8" fill="#F4EFE6" stroke="#E4DDD2" strokeWidth="1.5" />
{routes.map((r, i) => {
const len = Math.hypot(r.x2 - r.x1, r.y2 - r.y1);
const phase = ((tick + i * 12) % 40) / 40;
const px = r.x1 + (r.x2 - r.x1) * phase;
const py = r.y1 + (r.y2 - r.y1) * phase;
return (
<g key={i}>
<line x1={r.x1} y1={r.y1} x2={r.x2} y2={r.y2} stroke="#E4DDD2" strokeWidth="3" />
<circle cx={px} cy={py} r="4" fill="#D49A2A" opacity="0.9" />
</g>
);
})}
{blocks.map((b, i) => (
<g key={i}>
<rect x={b.x} y={b.y} width={b.w} height={b.h} rx="5" fill={b.color} opacity="0.85" />
<text x={b.x + b.w / 2} y={b.y + b.h / 2 + 4} textAnchor="middle" fill="#fff" fontSize="9" fontWeight="600">{b.label}</text>
</g>
))}
</svg>
);
}
function FutureTimelineDiagram() {
const [activeIdx, setActiveIdx] = useState(null);
const milestones = [
{ year: '۲۰۲۵', label: 'AGI اولیه', color: '#0F6B73' },
{ year: '۲۰۲۷', label: 'رایانش کوانتومی', color: '#D49A2A' },
{ year: '۲۰۲۹', label: 'رباتیک خودکار', color: '#C76D4A' },
{ year: '۲۰۳۱', label: 'رابط مغز-ماشین', color: '#2F8F6B' },
{ year: '۲۰۳۵', label: 'جوش هسته‌ای تجاری', color: '#0F6B73' },
];
const W = 480, H = 120;
return (
<svg width="100%" viewBox={`0 0 ${W} ${H + 20}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<line x1={40} y1={H / 2} x2={W - 40} y2={H / 2} stroke="#E4DDD2" strokeWidth="2" />
{milestones.map((m, i) => {
const x = 40 + (i / (milestones.length - 1)) * (W - 80);
const isH = activeIdx === i;
return (
<g key={i} onMouseEnter={() => setActiveIdx(i)} onMouseLeave={() => setActiveIdx(null)} style={{ cursor: 'pointer' }}>
<circle cx={x} cy={H / 2} r={isH ? 14 : 10} fill={m.color} style={{ transition: 'r 0.15s' }} />
<text x={x} y={H / 2 - 22} textAnchor="middle" fill={m.color} fontSize="10" fontWeight="700">{m.year}</text>
{isH && (
<g>
<rect x={x - 55} y={H / 2 + 20} width="110" height="22" rx="4" fill="#20343A" opacity="0.9" />
<text x={x} y={H / 2 + 34} textAnchor="middle" fill="#FAF7F0" fontSize="9">{m.label}</text>
</g>
)}
{!isH && <text x={x} y={H / 2 + 26} textAnchor="middle" fill="#5F6B6D" fontSize="8.5">{m.label}</text>}
</g>
);
})}
</svg>
);
}
function SoftwareArchDiagram() {
const modules = [
{ x: 180, y: 30, label: 'API Gateway', color: '#0F6B73' },
{ x: 60, y: 110, label: 'Auth Service', color: '#2F8F6B' },
{ x: 180, y: 110, label: 'Core Service', color: '#D49A2A' },
{ x: 300, y: 110, label: 'AI Service', color: '#C76D4A' },
{ x: 60, y: 190, label: 'Database', color: '#5F6B6D' },
{ x: 300, y: 190, label: 'Cache', color: '#5F6B6D' },
];
const edges = [[0,1],[0,2],[0,3],[1,4],[2,4],[3,5]];
return (
<svg width="100%" viewBox="0 0 420 250" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
{edges.map(([a, b], i) => (
<line key={i} x1={modules[a].x + 50} y1={modules[a].y + 18} x2={modules[b].x + 50} y2={modules[b].y + 18}
stroke="#E4DDD2" strokeWidth="1.5" markerEnd="url(#arr)" />
))}
<defs>
<marker id="arr" markerWidth="6" markerHeight="6" refX="3" refY="3" orient="auto">
<path d="M0,0 L6,3 L0,6 Z" fill="#E4DDD2" />
</marker>
</defs>
{modules.map((m, i) => (
<g key={i}>
<rect x={m.x} y={m.y} width="100" height="36" rx="6" fill={m.color} opacity="0.85" />
<text x={m.x + 50} y={m.y + 22} textAnchor="middle" fill="#fff" fontSize="9.5" fontWeight="600">{m.label}</text>
</g>
))}
</svg>
);
}
function WaveStreamDiagram() {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 40); return () => clearInterval(id); }, []);
const W = 480, H = 160;
const streams = [
{ color: '#D49A2A', amp: 28, freq: 0.022, phase: 0, y: 50 },
{ color: '#C46A4D', amp: 20, freq: 0.03, phase: 1.5, y: 85 },
{ color: '#2F8F6B', amp: 24, freq: 0.018, phase: 3, y: 120 },
];
const buildPath = (s) => {
const pts = Array.from({ length: 60 }, (_, i) => {
const x = (i / 59) * W;
const y = s.y + s.amp * Math.sin(x * s.freq + tick * 0.08 + s.phase);
return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`;
});
return pts.join(' ');
};
return (
<svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ fontFamily: 'Vazirmatn,sans-serif' }}>
<defs>
{streams.map((s, i) => (
<linearGradient key={i} id={`wg${i}`} x1="0" x2="1" y1="0" y2="0">
<stop offset="0%" stopColor={s.color} stopOpacity="0" />
<stop offset="30%" stopColor={s.color} stopOpacity="0.9" />
<stop offset="70%" stopColor={s.color} stopOpacity="0.9" />
<stop offset="100%" stopColor={s.color} stopOpacity="0" />
</linearGradient>
))}
</defs>
{streams.map((s, i) => (
<g key={i}>
<path d={buildPath(s)} fill="none" stroke={`url(#wg${i})`} strokeWidth={2.5} />
{(() => {
const pct = ((tick * 1.8 + i * 80) % 480) / 480;
const x = pct * W;
const y = s.y + s.amp * Math.sin(x * s.freq + tick * 0.08 + s.phase);
return <circle cx={x} cy={y} r={4} fill={s.color} opacity={0.9} />;
})()}
</g>
))}
<text x={W / 2} y={H - 4} textAnchor="middle" fill="#5F6B6D" fontSize="9">جریان داده در شبکه</text>
</svg>
);
}
function OrbitDiagram() {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 50); return () => clearInterval(id); }, []);
const cx = 140, cy = 110;
const orbits = [
{ r: 40, speed: 0.04, color: '#D49A2A', label: 'داده', dotR: 7 },
{ r: 65, speed: -0.025, color: '#C46A4D', label: 'مدل', dotR: 9 },
{ r: 90, speed: 0.016, color: '#2F8F6B', label: 'استنتاج', dotR: 8 },
];
return (
<svg width="100%" viewBox="0 0 280 220" style={{ fontFamily: 'Vazirmatn,sans-serif' }}>
<circle cx={cx} cy={cy} r={22} fill="#20343A" />
<circle cx={cx} cy={cy} r={16} fill="#0F6B73" opacity={0.8} />
<text x={cx} y={cy + 4} textAnchor="middle" fill="#FAF7F0" fontSize="8" fontWeight="700">AI</text>
{orbits.map((o, i) => (
<g key={i}>
<circle cx={cx} cy={cy} r={o.r} fill="none" stroke={o.color} strokeWidth="1" strokeDasharray="4 6" opacity="0.35" />
{(() => {
const angle = tick * o.speed;
const x = cx + o.r * Math.cos(angle);
const y = cy + o.r * Math.sin(angle);
return (
<g>
<circle cx={x} cy={y} r={o.dotR} fill={o.color} opacity={0.9} />
<text x={x} y={y + o.dotR + 10} textAnchor="middle" fill={o.color} fontSize="8" fontWeight="600">{o.label}</text>
</g>
);
})()}
</g>
))}
</svg>
);
}
function GeneratedDiagram({ variant = 1, compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick((t) => t + 1), 50); return () => clearInterval(id); }, []);
const W = compact ? 320 : 520;
const H = compact ? 150 : 210;
const seed = Number.isFinite(variant) ? variant : 1;
const nodeCount = 6 + (seed % 7);
const radius = compact ? 36 + (seed % 5) * 6 : 48 + (seed % 6) * 7;
const centerX = W * 0.5;
const centerY = H * 0.48;
const palette = ['#0F6B73', '#D49A2A', '#C76D4A', '#2F8F6B', '#5F6B6D'];
const points = Array.from({ length: nodeCount }, (_, i) => {
const angle = ((Math.PI * 2) / nodeCount) * i + (seed % 9) * 0.11;
return { x: centerX + Math.cos(angle) * radius, y: centerY + Math.sin(angle) * radius, color: palette[(i + seed) % palette.length] };
});
const pulse = (tick + seed * 3) % 100;
return (
<svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ fontFamily: 'Vazirmatn,sans-serif' }}>
<rect x="8" y="8" width={W - 16} height={H - 16} rx="12" fill="#F4EFE6" stroke="#E4DDD2" />
{points.map((a, i) => points.slice(i + 1).map((b, j) => (
<line key={`${i}-${j}`} x1={a.x} y1={a.y} x2={b.x} y2={b.y} stroke="#E4DDD2" strokeWidth={((i + j + seed) % 3) + 0.5} opacity={0.5} />
)))}
{points.map((p, i) => (
<g key={i}>
<circle cx={p.x} cy={p.y} r={6 + ((i + seed) % 4)} fill={p.color} opacity={0.9} />
<circle cx={p.x} cy={p.y} r={((pulse + i * 7) % 22) + 8} fill="none" stroke={p.color} opacity={0.16} />
</g>
))}
<text x={W / 2} y={H - 10} textAnchor="middle" fill="#5F6B6D" fontSize="9">Generated Diagram {String(seed).padStart(2, '0')}</text>
</svg>
);
}
function BrainDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 60); return () => clearInterval(id); }, []);
const W = compact ? 300 : 400, H = compact ? 180 : 260;
const cx = W / 2, cy = H * 0.45;
const nodes = [
{ x: cx, y: cy - 60 }, { x: cx - 50, y: cy - 30 }, { x: cx + 50, y: cy - 30 },
{ x: cx - 70, y: cy + 20 }, { x: cx + 70, y: cy + 20 }, { x: cx, y: cy + 60 },
{ x: cx - 30, y: cy + 40 }, { x: cx + 30, y: cy + 40 }
];
return (
<svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<defs>
<radialGradient id="brainGlow" cx="50%" cy="50%" r="50%">
<stop offset="0%" stopColor="#0F6B73" stopOpacity="0.3" />
<stop offset="100%" stopColor="#0F6B73" stopOpacity="0" />
</radialGradient>
</defs>
<circle cx={cx} cy={cy} r={80} fill="url(#brainGlow)" />
{nodes.map((n1, i) => nodes.slice(i + 1).map((n2, j) => {
const dist = Math.hypot(n1.x - n2.x, n1.y - n2.y);
if (dist > 100) return null;
return <line key={`${i}-${j}`} x1={n1.x} y1={n1.y} x2={n2.x} y2={n2.y} stroke="#0F6B73" strokeWidth="1" opacity="0.3" />;
}))}
{nodes.map((n, i) => {
const pulse = Math.sin(tick * 0.1 + i) * 3 + 6;
return <circle key={i} cx={n.x} cy={n.y} r={pulse} fill="#0F6B73" opacity="0.8" />;
})}
<text x={cx} y={H - 10} textAnchor="middle" fill="#5F6B6D" fontSize="10" fontWeight="600">رابط عصبی هوشمند</text>
</svg>
);
}
function DatabaseDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 50); return () => clearInterval(id); }, []);
const W = 320, H = 200;
const stacks = [
{ x: 60, y: 140, h: 40, color: '#5F6B6D' },
{ x: 160, y: 140, h: 60, color: '#D49A2A' },
{ x: 260, y: 140, h: 50, color: '#0F6B73' },
];
return (
<svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
{stacks.map((s, i) => (
<g key={i}>
<rect x={s.x - 25} y={s.y - s.h} width="50" height={s.h} fill={s.color} opacity="0.8" rx="4" />
<ellipse cx={s.x} cy={s.y - s.h} rx="25" ry="8" fill={s.color} />
<ellipse cx={s.x} cy={s.y} rx="25" ry="8" fill={s.color} stroke="#FAF7F0" strokeWidth="1" />
</g>
))}
<path d="M 60 80 Q 160 30 260 80" fill="none" stroke="#D49A2A" strokeWidth="2" strokeDasharray="5 5">
<animate attributeName="stroke-dashoffset" from="40" to="0" dur="2s" repeatCount="indefinite" />
</path>
<text x={W / 2} y={H - 5} textAnchor="middle" fill="#5F6B6D" fontSize="10">ساختار داده‌های برداری</text>
</svg>
);
}
function CloudDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 80); return () => clearInterval(id); }, []);
return (
<svg width="100%" viewBox="0 0 400 220" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<path d="M100,100 Q120,60 180,70 T260,100 T340,100 T300,140 L140,140 Z" fill="#F4EFE6" stroke="#0F6B73" strokeWidth="2" opacity="0.6" />
{[0, 1, 2].map(i => {
const x = 150 + i * 50, y = 110;
const pulse = (tick + i * 10) % 20 < 10;
return <rect key={i} x={x} y={y} width="30" height="15" rx="3" fill={pulse ? '#D49A2A' : '#5F6B6D'} opacity="0.9" />;
})}
<text x="200" y="170" textAnchor="middle" fill="#5F6B6D" fontSize="10">رایانش ابری و لبه شبکه</text>
</svg>
);
}
function QuantumDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 40); return () => clearInterval(id); }, []);
const cx1 = 120, cy = 100, cx2 = 280;
const orbit = tick * 0.05;
return (
<svg width="100%" viewBox="0 0 400 200" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<circle cx={cx1} cy={cy} r="30" fill="none" stroke="#2F8F6B" strokeWidth="1" strokeDasharray="4 4" />
<circle cx={cx2} cy={cy} r="30" fill="none" stroke="#2F8F6B" strokeWidth="1" strokeDasharray="4 4" />
<line x1={cx1} y1={cy} x2={cx2} y2={cy} stroke="#2F8F6B" strokeWidth="2" opacity="0.4" />
<circle cx={cx1 + Math.cos(orbit) * 30} cy={cy + Math.sin(orbit) * 30} r="6" fill="#2F8F6B" />
<circle cx={cx2 + Math.cos(orbit + Math.PI) * 30} cy={cy + Math.sin(orbit + Math.PI) * 30} r="6" fill="#2F8F6B" />
<text x="200" y="160" textAnchor="middle" fill="#5F6B6D" fontSize="10">درهم‌تنیدگی کوانتومی</text>
</svg>
);
}
function VlaDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 50); return () => clearInterval(id); }, []);
return (
<svg width="100%" viewBox="0 0 400 220" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<g transform="translate(200, 100)">
<rect x="-80" y="-40" width="160" height="80" rx="10" fill="#F4EFE6" stroke="#C76D4A" strokeWidth="2" />
<text x="0" y="5" textAnchor="middle" fill="#C76D4A" fontSize="14" fontWeight="800">VLA MODEL</text>
<line x1="-120" y1="-20" x2="-80" y2="-20" stroke="#0F6B73" strokeWidth="2">
<animate attributeName="stroke-dasharray" from="0,40" to="40,0" dur="1s" repeatCount="indefinite" />
</line>
<text x="-140" y="-17" textAnchor="middle" fill="#0F6B73" fontSize="9">Vision</text>
<line x1="-120" y1="20" x2="-80" y2="20" stroke="#D49A2A" strokeWidth="2" />
<text x="-140" y="23" textAnchor="middle" fill="#D49A2A" fontSize="9">Language</text>
<line x1="80" y1="0" x2="130" y2="0" stroke="#2F8F6B" strokeWidth="3" />
<text x="150" y="4" textAnchor="middle" fill="#2F8F6B" fontSize="10" fontWeight="700">ACTION</text>
</g>
</svg>
);
}
function DnaDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 60); return () => clearInterval(id); }, []);
const W = 320, H = 200;
const nodes = Array.from({ length: 10 }, (_, i) => i);
return (
<svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
{nodes.map(i => {
const y = 30 + i * 15;
const x1 = 160 + Math.sin(tick * 0.1 + i * 0.8) * 40;
const x2 = 160 - Math.sin(tick * 0.1 + i * 0.8) * 40;
return (
<g key={i}>
<line x1={x1} y1={y} x2={x2} y2={y} stroke="#E4DDD2" strokeWidth="1" />
<circle cx={x1} cy={y} r="5" fill="#C76D4A" />
<circle cx={x2} cy={y} r="5" fill="#0F6B73" />
</g>
);
})}
<text x={W / 2} y={H - 5} textAnchor="middle" fill="#5F6B6D" fontSize="10">مهندسی ژنتیک و بیوتکنولوژی</text>
</svg>
);
}
function FusionDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 40); return () => clearInterval(id); }, []);
const cx = 160, cy = 100;
return (
<svg width="100%" viewBox="0 0 320 200" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<circle cx={cx} cy={cy} r="50" fill="none" stroke="#D49A2A" strokeWidth="2" strokeDasharray="5 5">
<animateTransform attributeName="transform" type="rotate" from={`0 ${cx} ${cy}`} to={`360 ${cx} ${cy}`} dur="4s" repeatCount="indefinite" />
</circle>
<circle cx={cx} cy={cy} r={20 + Math.sin(tick * 0.2) * 5} fill="#D49A2A" opacity="0.8">
<animate attributeName="opacity" values="0.5;0.9;0.5" dur="1s" repeatCount="indefinite" />
</circle>
<text x={cx} y={cy + 75} textAnchor="middle" fill="#5F6B6D" fontSize="10">گداخت هسته‌ای و انرژی پاک</text>
</svg>
);
}
function SatelliteDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 50); return () => clearInterval(id); }, []);
const cx = 160, cy = 100;
const satX = cx + Math.cos(tick * 0.03) * 80;
const satY = cy + Math.sin(tick * 0.03) * 40;
return (
<svg width="100%" viewBox="0 0 320 200" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<circle cx={cx} cy={cy} r="30" fill="#0F6B73" opacity="0.6" />
<ellipse cx={cx} cy={cy} rx="80" ry="40" fill="none" stroke="#E4DDD2" strokeWidth="1" />
<g transform={`translate(${satX}, ${satY}) rotate(${tick * 1.7})`}>
<rect x="-8" y="-4" width="16" height="8" fill="#5F6B6D" />
<rect x="-15" y="-2" width="7" height="4" fill="#D49A2A" />
<rect x="8" y="-2" width="7" height="4" fill="#D49A2A" />
</g>
<line x1={cx} y1={cy} x2={satX} y2={satY} stroke="#0F6B73" strokeWidth="1" strokeDasharray="2 2" />
<text x={cx} y={H - 5} textAnchor="middle" fill="#5F6B6D" fontSize="10">ارتباطات ماهواره‌ای و فضا</text>
</svg>
);
}
function BlockchainDiagram({ compact = false }) {
const blocks = [0, 1, 2, 3];
return (
<svg width="100%" viewBox="0 0 400 150" style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
{blocks.map(i => (
<g key={i} transform={`translate(${40 + i * 90}, 50)`}>
<rect width="60" height="50" rx="6" fill="#F4EFE6" stroke="#2F8F6B" strokeWidth="2" />
<text x="30" y="30" textAnchor="middle" fill="#2F8F6B" fontSize="10" fontWeight="800">BLOCK {i}</text>
{i < 3 && <line x1="60" y1="25" x2="90" y2="25" stroke="#2F8F6B" strokeWidth="2" strokeDasharray="4 2" />}
</g>
))}
<text x="200" y="130" textAnchor="middle" fill="#5F6B6D" fontSize="10">فناوری زنجیره بلوکی و فین‌تک</text>
</svg>
);
}
function TekRagThreeDiagram({ variant = 'corpus', compact = false }) {
const hostRef = useRef(null);
const [hoverLabel, setHoverLabel] = useState('TekRAG-Persian');
useEffect(() => {
const host = hostRef.current;
if (!host) return undefined;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 3.2, 8.5);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
renderer.outputColorSpace = THREE.SRGBColorSpace;
host.appendChild(renderer.domElement);
const group = new THREE.Group();
scene.add(group);
scene.add(new THREE.AmbientLight(0xffffff, 0.7));
const key = new THREE.DirectionalLight(0xffffff, 1.4);
key.position.set(4, 6, 5);
scene.add(key);
const rim = new THREE.DirectionalLight(0xd49a2a, 0.8);
rim.position.set(-5, 3, -4);
scene.add(rim);
const pickables = [];
const palette = {
teal: 0x0f6b73,
gold: 0xd49a2a,
clay: 0xc76d4a,
green: 0x2f8f6b,
ink: 0x20343a,
line: 0xe4ddd2,
red: 0xc94c4c,
cream: 0xf4efe6,
};
const addLabel = (object, label) => {
object.userData.label = label;
pickables.push(object);
return object;
};
const box = (label, position, scale, color, opacity = 0.92) => {
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(scale[0], scale[1], scale[2]),
new THREE.MeshStandardMaterial({ color, roughness: 0.48, metalness: 0.12, transparent: opacity < 1, opacity })
);
mesh.position.set(...position);
group.add(addLabel(mesh, label));
const edges = new THREE.LineSegments(
new THREE.EdgesGeometry(mesh.geometry),
new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.18 })
);
mesh.add(edges);
return mesh;
};
const sphere = (label, position, radius, color, opacity = 0.95) => {
const mesh = new THREE.Mesh(
new THREE.SphereGeometry(radius, 28, 18),
new THREE.MeshStandardMaterial({ color, roughness: 0.35, metalness: 0.2, transparent: opacity < 1, opacity })
);
mesh.position.set(...position);
group.add(addLabel(mesh, label));
return mesh;
};
const line = (from, to, color = palette.line, opacity = 0.45) => {
const geometry = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(...from),
new THREE.Vector3(...to),
]);
const mesh = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color, transparent: true, opacity }));
group.add(mesh);
return mesh;
};
if (variant === 'corpus') {
const layers = [
['Raw HTML export', -1.8, palette.ink],
['Persian normalization', -0.6, palette.teal],
['Heading-aware chunks', 0.6, palette.gold],
['Metadata and provenance', 1.8, palette.green],
];
layers.forEach(([label, y, color], idx) => {
const slab = box(label, [0, y, 0], [5.8, 0.22, 3.2], color, 0.42);
slab.rotation.y = idx % 2 ? 0.08 : -0.08;
for (let i = 0; i < 9; i += 1) {
const x = -2.2 + (i % 3) * 2.2 + (idx % 2 ? 0.15 : -0.1);
const z = -1.05 + Math.floor(i / 3) * 1.05;
const doc = sphere(`${label}: document ${i + 1}`, [x, y + 0.28, z], 0.09, idx % 2 ? palette.cream : palette.gold, 0.82);
doc.scale.y = 0.55;
}
});
for (let i = 0; i < 8; i += 1) {
const x = -2.3 + (i % 4) * 1.55;
const z = -1.35 + (i % 2) * 2.7;
line([x, -1.65, z], [x * 0.72, 1.95, z * 0.55], palette.gold, 0.36);
}
sphere('Benchmark release: QA plus evidence IDs', [0, 2.45, 0], 0.38, palette.clay);
camera.position.set(0, 4.1, 8.2);
} else if (variant === 'retrieval') {
line([-3.3, 0, 0], [3.3, 0, 0], palette.teal, 0.5);
line([0, -2.2, 0], [0, 2.2, 0], palette.gold, 0.5);
line([0, 0, -2.8], [0, 0, 2.8], palette.green, 0.5);
const clusters = [
['BM25 exact acronym region', [-1.75, 0.45, -0.6], palette.gold],
['Dense semantic Persian region', [1.55, 0.1, 0.75], palette.teal],
['Hybrid fused evidence region', [0.2, 1.2, -0.1], palette.green],
];
clusters.forEach(([label, center, color], ci) => {
sphere(label, center, 0.3, color, 0.82);
for (let i = 0; i < 18; i += 1) {
const a = (i / 18) * Math.PI * 2;
const r = 0.35 + (i % 5) * 0.09;
const p = [
center[0] + Math.cos(a) * r,
center[1] + Math.sin(a * 1.7) * 0.38,
center[2] + Math.sin(a) * r,
];
sphere(`${label}: chunk ${i + 1}`, p, 0.055, color, 0.76);
}
});
const query = sphere('Persian technical user query', [-3.0, -1.45, 1.7], 0.22, palette.red);
clusters.forEach(([, center], i) => line(query.position.toArray(), center, i === 1 ? palette.teal : palette.gold, 0.48));
box('Reranker: top-k evidence gate', [0, -1.55, 0], [1.9, 0.16, 1.0], palette.ink, 0.68);
camera.position.set(0.2, 2.9, 7.4);
} else {
const metrics = [
['Recall@k', -2.4, 1.55, palette.teal],
['Citation precision', -1.2, 2.1, palette.green],
['Atomic support precision', 0, 2.45, palette.gold],
['Abstention F1', 1.2, 1.65, palette.clay],
['Unsupported-claim rate', 2.4, 0.9, palette.red],
];
metrics.forEach(([label, x, h, color]) => {
const pillar = box(label, [x, h / 2 - 1.2, 0], [0.52, h, 0.52], color, 0.9);
const cap = sphere(`${label}: confidence interval marker`, [x, h - 1.0, 0], 0.18, color, 0.95);
line([x, h - 1.0, -0.65], [x, h - 1.0, 0.65], color, 0.48);
pillar.rotation.y = 0.2;
cap.scale.y = 0.7;
});
const ringGeo = new THREE.TorusGeometry(1.55, 0.025, 12, 96);
const ring = new THREE.Mesh(ringGeo, new THREE.MeshStandardMaterial({ color: palette.teal, transparent: true, opacity: 0.5 }));
ring.rotation.x = Math.PI / 2;
ring.position.y = -1.05;
group.add(addLabel(ring, 'Paired statistical testing and confidence intervals'));
for (let i = 0; i < 14; i += 1) {
const a = (i / 14) * Math.PI * 2;
sphere('Hallucination error atom', [Math.cos(a) * 1.55, -1.05, Math.sin(a) * 1.55], 0.065, i % 3 === 0 ? palette.red : palette.gold, 0.82);
}
camera.position.set(0, 3.0, 7.2);
}
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
let raf = 0;
let dragging = false;
let lastX = 0;
let lastY = 0;
let targetX = -0.16;
let targetY = 0.34;
renderer.domElement.style.display = 'block';
const resize = () => {
const rect = host.getBoundingClientRect();
const width = Math.max(rect.width || host.offsetWidth || 600, 280);
const height = compact ? 240 : 340;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
};
resize();
requestAnimationFrame(resize);
const resizeObserver = new ResizeObserver(resize);
resizeObserver.observe(host);
const updatePointer = (event) => {
const rect = renderer.domElement.getBoundingClientRect();
pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
const hit = raycaster.intersectObjects(pickables, true)[0];
const label = hit?.object?.userData?.label || hit?.object?.parent?.userData?.label;
if (label) setHoverLabel(label);
if (dragging) {
targetY += (event.clientX - lastX) * 0.008;
targetX += (event.clientY - lastY) * 0.006;
lastX = event.clientX;
lastY = event.clientY;
}
};
const pointerDown = (event) => {
dragging = true;
lastX = event.clientX;
lastY = event.clientY;
renderer.domElement.setPointerCapture?.(event.pointerId);
};
const pointerUp = (event) => {
dragging = false;
renderer.domElement.releasePointerCapture?.(event.pointerId);
};
renderer.domElement.addEventListener('pointermove', updatePointer);
renderer.domElement.addEventListener('pointerdown', pointerDown);
renderer.domElement.addEventListener('pointerup', pointerUp);
renderer.domElement.addEventListener('pointerleave', pointerUp);
const animate = () => {
targetY += dragging ? 0 : 0.003;
group.rotation.x += (targetX - group.rotation.x) * 0.08;
group.rotation.y += (targetY - group.rotation.y) * 0.08;
renderer.render(scene, camera);
raf = requestAnimationFrame(animate);
};
animate();
return () => {
cancelAnimationFrame(raf);
resizeObserver.disconnect();
renderer.domElement.removeEventListener('pointermove', updatePointer);
renderer.domElement.removeEventListener('pointerdown', pointerDown);
renderer.domElement.removeEventListener('pointerup', pointerUp);
renderer.domElement.removeEventListener('pointerleave', pointerUp);
renderer.dispose();
scene.traverse((object) => {
object.geometry?.dispose?.();
if (Array.isArray(object.material)) object.material.forEach((m) => m.dispose?.());
else object.material?.dispose?.();
});
host.replaceChildren();
};
}, [variant, compact]);
const labels = {
corpus: ['Raw', 'Cleaned', 'Metadata', 'Provenance'],
retrieval: ['BM25', 'Dense', 'Hybrid', 'Rerank'],
evaluation: ['Recall', 'Citation', 'Support', 'Abstention'],
}[variant] || ['TekRAG', 'RAG', 'QA'];
return (
<div className="tekrag-3d-shell" style={{ direction: 'ltr', textAlign: 'left' }}>
<div ref={hostRef} className="tekrag-3d-canvas" data-diagram-3d={variant} style={{ width: '100%', minHeight: compact ? 240 : 340, borderRadius: 12, overflow: 'hidden', background: 'radial-gradient(circle at 50% 20%, #ffffff 0%, #f4efe6 42%, #e9f2f2 100%)' }} />
<div className="tekrag-3d-overlay" style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', alignItems: 'center', marginTop: 10 }}>
<div style={{ fontSize: 12, color: '#0F6B73', fontWeight: 800, lineHeight: 1.6 }}>{hoverLabel}</div>
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
{labels.map((label) => <span key={label} style={{ fontSize: 10, color: '#5F6B6D', border: '1px solid #E4DDD2', borderRadius: 999, padding: '2px 8px', background: '#fff' }}>{label}</span>)}
</div>
</div>
</div>
);
}
function BillingDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => (t + 1) % 120), 80); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const bars = [
{ label: 'Input', base: 40, peak: 110, color: '#0F6B73' },
{ label: 'Output', base: 55, peak: 140, color: '#D49A2A' },
{ label: 'Cache', base: 20, peak: 70, color: '#2F8F6B' },
{ label: 'Image', base: 65, peak: 160, color: '#C76D4A' },
{ label: 'Audio', base: 30, peak: 90, color: '#5F6B6D' },
];
const progress = (Math.sin(tick * 0.08) + 1) / 2;
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
{bars.map((b, i) => {
const bh = b.base + (b.peak - b.base) * progress;
const x = 40 + i * 72;
return (
<g key={i}>
<rect x={x} y={h - 50 - bh} width={48} height={bh} rx="4" fill={b.color} opacity="0.85" />
<rect x={x} y={h - 50 - bh} width={48} height={8} rx="4" fill={b.color} />
<text x={x + 24} y={h - 32} textAnchor="middle" fill="#263238" fontSize="9">{b.label}</text>
<text x={x + 24} y={h - 55 - bh} textAnchor="middle" fill={b.color} fontSize="10" fontWeight="700">{Math.round(b.base + (b.peak - b.base) * progress)}k</text>
</g>
);
})}
<text x="210" y="22" textAnchor="middle" fill="#0F6B73" fontSize="12" fontWeight="700">Token Usage</text>
<line x1="30" y1={h - 50} x2="390" y2={h - 50} stroke="#E4DDD2" strokeWidth="1.5" />
{[0, 40, 80, 120, 160].map((v, i) => (
<text key={i} x="28" y={h - 50 - v} textAnchor="end" fill="#5F6B6D" fontSize="8">{v}k</text>
))}
</svg>
);
}
function LegalDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 100); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const tilt = Math.sin(tick * 0.05) * 12;
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
<line x1="210" y1="30" x2="210" y2={h - 40} stroke="#263238" strokeWidth="3" />
<line x1="210" y1="50" x2="130" y2={60 + tilt} stroke="#263238" strokeWidth="2" />
<line x1="210" y1="50" x2="290" y2={60 - tilt} stroke="#263238" strokeWidth="2" />
<ellipse cx="130" cy={65 + tilt} rx="36" ry="14" fill="#0F6B73" opacity="0.15" stroke="#0F6B73" strokeWidth="1.5" />
<text x="130" y={69 + tilt} textAnchor="middle" fill="#0F6B73" fontSize="9" fontWeight="700">AI Product</text>
<ellipse cx="290" cy={65 - tilt} rx="36" ry="14" fill="#C76D4A" opacity="0.15" stroke="#C76D4A" strokeWidth="1.5" />
<text x="290" y={69 - tilt} textAnchor="middle" fill="#C76D4A" fontSize="9" fontWeight="700">Liability</text>
<rect x="200" y={h - 40} width="20" height="14" rx="2" fill="#D49A2A" opacity="0.8" />
<text x="210" y="24" textAnchor="middle" fill="#263238" fontSize="11" fontWeight="700">AI Legal Scales</text>
{['CEO', 'Product', 'Corp'].map((t, i) => (
<g key={i}>
<circle cx={80 + i * 60} cy={h - 60} r="16" fill={['#0F6B73','#2F8F6B','#D49A2A'][i]} opacity="0.2" stroke={['#0F6B73','#2F8F6B','#D49A2A'][i]} strokeWidth="1.5" />
<text x={80 + i * 60} y={h - 56} textAnchor="middle" fill={['#0F6B73','#2F8F6B','#D49A2A'][i]} fontSize="8">{t}</text>
</g>
))}
</svg>
);
}
function MathDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 60); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const nodes = [
{ x: 210, y: 60, label: 'v₁', color: '#D49A2A' },
{ x: 120, y: 120, label: 'v₂', color: '#0F6B73' },
{ x: 300, y: 120, label: 'v₃', color: '#0F6B73' },
{ x: 80, y: 200, label: 'v₄', color: '#2F8F6B' },
{ x: 170, y: 200, label: 'v₅', color: '#2F8F6B' },
{ x: 250, y: 200, label: 'v₆', color: '#2F8F6B' },
{ x: 340, y: 200, label: 'v₇', color: '#C76D4A' },
];
const edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6],[3,4],[4,5],[5,6]];
const pulse = (tick % 60) / 60;
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
{edges.map(([a,b], i) => {
const p = (tick * 0.02 + i * 0.3) % 1;
const mx = nodes[a].x + (nodes[b].x - nodes[a].x) * p;
const my = nodes[a].y + (nodes[b].y - nodes[a].y) * p;
return (
<g key={i}>
<line x1={nodes[a].x} y1={nodes[a].y} x2={nodes[b].x} y2={nodes[b].y} stroke="#E4DDD2" strokeWidth="1.5" />
<circle cx={mx} cy={my} r="3" fill="#D49A2A" opacity="0.8" />
</g>
);
})}
{nodes.map((n, i) => (
<g key={i}>
<circle cx={n.x} cy={n.y} r="16" fill={n.color} opacity="0.15" stroke={n.color} strokeWidth="2" />
<text x={n.x} y={n.y + 4} textAnchor="middle" fill={n.color} fontSize="11" fontWeight="700">{n.label}</text>
</g>
))}
<text x="210" y={h - 14} textAnchor="middle" fill="#5F6B6D" fontSize="10">Unit Distance Graph — Erdős Conjecture</text>
</svg>
);
}
function AgentLoopDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 50); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const cx = 210, cy = h / 2, r = compact ? 70 : 90;
const steps = ['Plan', 'Act', 'Observe', 'Reflect'];
const colors = ['#0F6B73', '#D49A2A', '#2F8F6B', '#C76D4A'];
const active = Math.floor(tick / 30) % 4;
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
{steps.map((s, i) => {
const angle = (i / 4) * Math.PI * 2 - Math.PI / 2;
const nx = cx + Math.cos(angle) * r, ny = cy + Math.sin(angle) * r;
const next = (i + 1) % 4;
const na = (next / 4) * Math.PI * 2 - Math.PI / 2;
const nx2 = cx + Math.cos(na) * r, ny2 = cy + Math.sin(na) * r;
const p = (tick % 30) / 30;
const px = nx + (nx2 - nx) * p, py = ny + (ny2 - ny) * p;
return (
<g key={i}>
<line x1={nx} y1={ny} x2={nx2} y2={ny2} stroke={colors[i]} strokeWidth="2" opacity="0.4" strokeDasharray="4 3" />
{active === i && <circle cx={px} cy={py} r="5" fill={colors[i]} opacity="0.9" />}
<circle cx={nx} cy={ny} r={active === i ? 22 : 18} fill={colors[i]} opacity={active === i ? 0.25 : 0.12} stroke={colors[i]} strokeWidth="2" />
<text x={nx} y={ny + 4} textAnchor="middle" fill={colors[i]} fontSize="9" fontWeight="700">{s}</text>
</g>
);
})}
<circle cx={cx} cy={cy} r="22" fill="#263238" opacity="0.08" />
<text x={cx} y={cy + 4} textAnchor="middle" fill="#263238" fontSize="10" fontWeight="700">Agent</text>
</svg>
);
}
function GeopoliticsDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 70); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const regions = [
{ x: 100, y: 80, label: 'US', color: '#0F6B73' },
{ x: 200, y: 60, label: 'EU', color: '#D49A2A' },
{ x: 310, y: 80, label: 'China', color: '#C76D4A' },
{ x: 80, y: 180, label: 'India', color: '#2F8F6B' },
{ x: 200, y: 190, label: 'MENA', color: '#5F6B6D' },
{ x: 330, y: 180, label: 'APAC', color: '#0F6B73' },
];
const links = [[0,1],[0,3],[1,2],[1,4],[2,5],[3,4],[4,5]];
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
<ellipse cx="210" cy="140" rx="190" ry="100" fill="none" stroke="#E4DDD2" strokeWidth="1" strokeDasharray="6 4" opacity="0.6" />
{links.map(([a, b], i) => {
const p = (tick * 0.015 + i * 0.2) % 1;
const mx = regions[a].x + (regions[b].x - regions[a].x) * p;
const my = regions[a].y + (regions[b].y - regions[a].y) * p;
return (
<g key={i}>
<line x1={regions[a].x} y1={regions[a].y} x2={regions[b].x} y2={regions[b].y} stroke="#E4DDD2" strokeWidth="1.5" />
<circle cx={mx} cy={my} r="3.5" fill={regions[a].color} opacity="0.85" />
</g>
);
})}
{regions.map((n, i) => (
<g key={i}>
<circle cx={n.x} cy={n.y} r="20" fill={n.color} opacity="0.15" stroke={n.color} strokeWidth="2" />
<text x={n.x} y={n.y + 4} textAnchor="middle" fill={n.color} fontSize="9" fontWeight="700">{n.label}</text>
</g>
))}
<text x="210" y={h - 14} textAnchor="middle" fill="#5F6B6D" fontSize="10">Geopolitical AI Ecosystem</text>
</svg>
);
}
function BrowserDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 90); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const reqs = [0, 1, 2, 3, 4].map(i => ({ label: ['HTML','CSS','JS','API','WS'][i], color: ['#0F6B73','#D49A2A','#C76D4A','#2F8F6B','#5F6B6D'][i], w: [160,80,120,100,60][i] }));
const progress = (tick % 60) / 60;
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
<rect x="20" y="20" width="380" height="26" rx="6" fill="#263238" opacity="0.08" />
<circle cx="38" cy="33" r="5" fill="#C76D4A" opacity="0.7" />
<circle cx="54" cy="33" r="5" fill="#D49A2A" opacity="0.7" />
<circle cx="70" cy="33" r="5" fill="#2F8F6B" opacity="0.7" />
<rect x="84" y="26" width="260" height="14" rx="4" fill="#fff" opacity="0.5" />
<text x="214" y="36" textAnchor="middle" fill="#263238" fontSize="8" opacity="0.6">teknav.ir/article/...</text>
{reqs.map((r, i) => {
const y = 58 + i * 34;
const filled = Math.min(r.w, r.w * (((tick + i * 12) % 60) / 60) * 1.8);
return (
<g key={i}>
<text x="75" y={y + 10} textAnchor="end" fill="#5F6B6D" fontSize="9">{r.label}</text>
<rect x="80" y={y} width={r.w} height="18" rx="3" fill="#E4DDD2" />
<rect x="80" y={y} width={Math.min(filled, r.w)} height="18" rx="3" fill={r.color} opacity="0.75" />
<text x={83} y={y + 12} fill="#fff" fontSize="8" opacity="0.9">{Math.round(Math.min(filled, r.w) / r.w * 100)}%</text>
</g>
);
})}
<text x="210" y={h - 14} textAnchor="middle" fill="#5F6B6D" fontSize="10">Browser DevTools — Network</text>
</svg>
);
}
function MemorySafetyDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 80); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const blocks = [
{ x: 30, label: 'Stack', owned: true },
{ x: 110, label: 'Heap A', owned: true },
{ x: 190, label: 'Heap B', owned: false },
{ x: 270, label: 'Heap C', owned: true },
{ x: 350, label: 'Static', owned: true },
];
const flash = Math.sin(tick * 0.15) > 0.7;
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
<text x="210" y="22" textAnchor="middle" fill="#263238" fontSize="11" fontWeight="700">Memory Safety — Rust Ownership</text>
{blocks.map((b, i) => {
const isUnsafe = !b.owned;
const color = isUnsafe ? '#C76D4A' : '#2F8F6B';
const bh = 60 + Math.sin(tick * 0.05 + i) * 10;
return (
<g key={i}>
<rect x={b.x} y={h - 60 - bh} width="60" height={bh} rx="4" fill={color} opacity={isUnsafe && flash ? 0.9 : 0.2} stroke={color} strokeWidth="2" />
<text x={b.x + 30} y={h - 63 - bh} textAnchor="middle" fill={color} fontSize="8" fontWeight="700">{b.owned ? '✓' : '✗'}</text>
<text x={b.x + 30} y={h - 40} textAnchor="middle" fill={color} fontSize="8">{b.label}</text>
</g>
);
})}
<rect x="185" y={h - 120} width="70" height="20" rx="4" fill="#C76D4A" opacity={flash ? 0.3 : 0.1} stroke="#C76D4A" strokeWidth="1" strokeDasharray="3 2" />
<text x="220" y={h - 107} textAnchor="middle" fill="#C76D4A" fontSize="8">use-after-free</text>
<line x1="30" y1={h - 55} x2="390" y2={h - 55} stroke="#E4DDD2" strokeWidth="1.5" />
</svg>
);
}
function MediaDiagram({ compact = false }) {
const [tick, setTick] = useState(0);
useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 60); return () => clearInterval(id); }, []);
const h = compact ? 200 : 280;
const nodes = [
{ x: 60, y: h / 2, label: 'نویسنده', color: '#D49A2A', r: 22 },
{ x: 210, y: h / 2 - 30, label: 'پلتفرم', color: '#0F6B73', r: 28 },
{ x: 210, y: h / 2 + 30, label: 'RSS/Feed', color: '#2F8F6B', r: 20 },
{ x: 360, y: h / 2 - 60, label: 'خواننده ۱', color: '#5F6B6D', r: 16 },
{ x: 360, y: h / 2, label: 'خواننده ۲', color: '#5F6B6D', r: 16 },
{ x: 360, y: h / 2 + 60, label: 'خواننده ۳', color: '#5F6B6D', r: 16 },
];
const edges = [[0,1],[0,2],[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]];
return (
<svg width="100%" viewBox={`0 0 420 ${h}`} style={{ fontFamily: 'Vazirmatn, sans-serif' }}>
<rect x="0" y="0" width="420" height={h} rx="12" fill="#FAF7F0" />
{edges.map(([a, b], i) => {
const p = (tick * 0.02 + i * 0.15) % 1;
const mx = nodes[a].x + (nodes[b].x - nodes[a].x) * p;
const my = nodes[a].y + (nodes[b].y - nodes[a].y) * p;
return (
<g key={i}>
<line x1={nodes[a].x} y1={nodes[a].y} x2={nodes[b].x} y2={nodes[b].y} stroke="#E4DDD2" strokeWidth="1.5" opacity="0.8" />
<circle cx={mx} cy={my} r="3" fill={nodes[a].color} opacity="0.85" />
</g>
);
})}
{nodes.map((n, i) => (
<g key={i}>
<circle cx={n.x} cy={n.y} r={n.r} fill={n.color} opacity="0.15" stroke={n.color} strokeWidth="2" />
<text x={n.x} y={n.y + 4} textAnchor="middle" fill={n.color} fontSize="8" fontWeight="700">{n.label}</text>
</g>
))}
<text x="210" y={h - 14} textAnchor="middle" fill="#5F6B6D" fontSize="10">Content Distribution Network</text>
</svg>
);
}
function DiagramRenderer({ type, compact = false }) {
const map = {
neural: NeuralNetworkDiagram,
pipeline: DataPipelineDiagram,
cyber: CyberSecurityDiagram,
growth: StartupGrowthDiagram,
chip: HardwareChipDiagram,
timeline: FutureTimelineDiagram,
arch: SoftwareArchDiagram,
wave: WaveStreamDiagram,
orbit: OrbitDiagram,
brain: BrainDiagram,
database: DatabaseDiagram,
cloud: CloudDiagram,
quantum: QuantumDiagram,
vla: VlaDiagram,
dna: DnaDiagram,
fusion: FusionDiagram,
satellite: SatelliteDiagram,
blockchain: BlockchainDiagram,
billing: BillingDiagram,
legal: LegalDiagram,
math: MathDiagram,
'agent-loop': AgentLoopDiagram,
geopolitics: GeopoliticsDiagram,
browser: BrowserDiagram,
'memory-safety': MemorySafetyDiagram,
media: MediaDiagram,
'tekrag-corpus-3d': (props) => <TekRagThreeDiagram {...props} variant="corpus" />,
'tekrag-retrieval-3d': (props) => <TekRagThreeDiagram {...props} variant="retrieval" />,
'tekrag-evaluation-3d': (props) => <TekRagThreeDiagram {...props} variant="evaluation" />
};
if (typeof type === 'string' && /^diagram-\d{3}$/.test(type)) {
const variant = Number(type.split('-')[1]);
return <GeneratedDiagram compact={compact} variant={variant} />;
}
const Comp = map[type] || NeuralNetworkDiagram;
return <Comp compact={compact} />;
}
export { NeuralNetworkDiagram, DataPipelineDiagram, CyberSecurityDiagram, StartupGrowthDiagram, HardwareChipDiagram, FutureTimelineDiagram, SoftwareArchDiagram, WaveStreamDiagram, OrbitDiagram, GeneratedDiagram, TekRagThreeDiagram, BillingDiagram, LegalDiagram, MathDiagram, AgentLoopDiagram, GeopoliticsDiagram, BrowserDiagram, MemorySafetyDiagram, MediaDiagram, DiagramRenderer };