{"spec_id":"eye-diagram-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// eye-diagram-basic: Signal Integrity Eye Diagram\n// Library: muix 7.29.1 | JavaScript 22.22.3\n// Quality: 84/100 | Created: 2026-06-18\n//# anyplot-orientation: landscape\n// anyplot.ai\n// eye-diagram-basic: Signal Integrity Eye Diagram\n// Library: MUI X Charts | React | Node 22\n// License: @mui/x-charts — MIT (community). Pro/Premium are out of scope.\n// Quality: pending | Created: 2026-06-18\n\nimport { ScatterChart } from \"@mui/x-charts/ScatterChart\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Seeded LCG for reproducible data generation\nlet _s = 42;\nfunction rand(): number {\n  _s = (Math.imul(1664525, _s) + 1013904223) >>> 0;\n  return _s / 0x100000000;\n}\nfunction randn(): number {\n  const u = rand() || 1e-10;\n  return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * rand());\n}\n\n// NRZ eye diagram: 300 overlaid traces, each 2 UI long, 200 samples per trace\nconst N_TRACES = 300;\nconst N_SAMPLES = 200;\n\nfunction sigm(x: number): number {\n  return 1 / (1 + Math.exp(-12 * x));\n}\n\n// Generate raw trace points: sigmoid transitions + random jitter + Gaussian noise\nconst rawPts: Array<{ x: number; y: number }> = [];\nfor (let i = 0; i < N_TRACES; i++) {\n  const b0 = rand() > 0.5 ? 1 : 0;\n  const b1 = rand() > 0.5 ? 1 : 0;\n  const b2 = rand() > 0.5 ? 1 : 0;\n  const j0 = randn() * 0.03;\n  const j1 = randn() * 0.03;\n  for (let s = 0; s < N_SAMPLES; s++) {\n    const time = (s / (N_SAMPLES - 1)) * 2;\n    const voltage =\n      b0 +\n      (b1 - b0) * sigm(time - j0) +\n      (b2 - b1) * sigm(time - 1 - j1) +\n      randn() * 0.05;\n    rawPts.push({ x: time, y: voltage });\n  }\n}\n\n// Bin all trace points into a 2D density grid (time × voltage)\nconst TB = 60;\nconst VB = 36;\nconst V0 = -0.2;\nconst V1 = 1.2;\nconst grid = new Int32Array(TB * VB);\nfor (const p of rawPts) {\n  if (p.y < V0 || p.y > V1) continue;\n  const ti = Math.min(Math.floor((p.x / 2) * TB), TB - 1);\n  const vi = Math.min(Math.floor(((p.y - V0) / (V1 - V0)) * VB), VB - 1);\n  if (ti >= 0 && vi >= 0) grid[ti * VB + vi]++;\n}\n\n// Convert non-zero cells to scatter data with log-density for color mapping\nconst eyeData: Array<{ id: number; x: number; y: number; z: number }> = [];\nlet maxZ = 0;\nfor (let ti = 0; ti < TB; ti++) {\n  for (let vi = 0; vi < VB; vi++) {\n    const d = grid[ti * VB + vi];\n    if (d > 0) {\n      const z = Math.log(d + 1);\n      if (z > maxZ) maxZ = z;\n      eyeData.push({\n        id: ti * VB + vi,\n        x: ((ti + 0.5) / TB) * 2,\n        y: V0 + ((vi + 0.5) / VB) * (V1 - V0),\n        z,\n      });\n    }\n  }\n}\n\nconst TITLE_H = 52;\nconst COLORBAR_H = 52;\n\nexport default function Chart() {\n  const W = window.ANYPLOT_SIZE.width;\n  const H = window.ANYPLOT_SIZE.height;\n  const chartH = H - TITLE_H - COLORBAR_H;\n\n  return (\n    <Box\n      width={W}\n      height={H}\n      sx={{\n        background: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        overflow: \"hidden\",\n      }}\n    >\n      <Typography\n        sx={{\n          fontSize: \"22px\",\n          fontWeight: 500,\n          color: t.ink,\n          px: \"32px\",\n          pt: \"16px\",\n          pb: \"4px\",\n          lineHeight: 1.2,\n          textAlign: \"center\",\n        }}\n      >\n        eye-diagram-basic · javascript · muix · anyplot.ai\n      </Typography>\n      <ScatterChart\n        width={W}\n        height={chartH}\n        skipAnimation\n        margin={{ left: 70, right: 40, top: 20, bottom: 60 }}\n        grid={{ vertical: false, horizontal: true }}\n        zAxis={[\n          {\n            id: \"density\",\n            min: 0,\n            max: maxZ,\n            colorMap: {\n              type: \"continuous\",\n              min: 0,\n              max: maxZ,\n              color: [t.seq[0], t.seq[1]] as [string, string],\n            },\n          },\n        ]}\n        series={[\n          {\n            data: eyeData,\n            markerSize: 9,\n            zAxisId: \"density\",\n          },\n        ]}\n        xAxis={[\n          {\n            label: \"Time (UI)\",\n            min: 0,\n            max: 2,\n            tickNumber: 5,\n            labelStyle: { fontSize: 15, fontWeight: 500, fill: t.ink },\n            tickLabelStyle: { fontSize: 13, fill: t.inkSoft },\n          },\n        ]}\n        yAxis={[\n          {\n            label: \"Voltage (V)\",\n            min: V0,\n            max: V1,\n            tickNumber: 7,\n            labelStyle: { fontSize: 15, fontWeight: 500, fill: t.ink },\n            tickLabelStyle: { fontSize: 13, fill: t.inkSoft },\n          },\n        ]}\n      />\n      {/* Density scale colorbar */}\n      <Box\n        sx={{\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          gap: \"12px\",\n          pb: \"14px\",\n        }}\n      >\n        <Typography sx={{ fontSize: \"13px\", color: t.inkSoft }}>\n          Low density\n        </Typography>\n        <Box\n          sx={{\n            width: 200,\n            height: 14,\n            borderRadius: \"3px\",\n            background: `linear-gradient(to right, ${t.seq[0]}, ${t.seq[1]})`,\n          }}\n        />\n        <Typography sx={{ fontSize: \"13px\", color: t.inkSoft }}>\n          High density\n        </Typography>\n      </Box>\n    </Box>\n  );\n}\n"}