{"spec_id":"spectrum-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// spectrum-basic: Frequency Spectrum Plot\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-09\nimport { LineChart } from \"@mui/x-charts/LineChart\";\nimport { ChartsReferenceLine } from \"@mui/x-charts/ChartsReferenceLine\";\nimport { Typography } from \"@mui/material\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ---------------------------------------\n// Synthetic FFT magnitude spectrum of a plucked low-E guitar string (82.4 Hz)\n// and its first four harmonics, riding on a gently sloping noise floor.\nlet seed = 42;\nfunction lcg() {\n  seed = (Math.imul(seed, 1103515245) + 12345) | 0;\n  return (seed >>> 0) / 4294967296;\n}\n\nconst FUNDAMENTAL_HZ = 82.4;\nconst HARMONICS = [1, 2, 3, 4, 5].map((n) => ({\n  freq: FUNDAMENTAL_HZ * n,\n  amplitudeDb: -6 - (n - 1) * 8,\n  widthDecades: 0.04 + n * 0.008,\n}));\n\nconst POINTS = 400;\nconst MIN_FREQ = 20;\nconst MAX_FREQ = 8000;\nconst logMin = Math.log10(MIN_FREQ);\nconst logMax = Math.log10(MAX_FREQ);\n\nconst frequency = [];\nconst amplitude = [];\nfor (let i = 0; i < POINTS; i++) {\n  const f = Math.pow(10, logMin + (logMax - logMin) * (i / (POINTS - 1)));\n  frequency.push(Math.round(f * 10) / 10);\n\n  // Pink-noise-like floor: drops with frequency, plus small fixed jitter\n  const noiseFloorDb = -55 - 6 * Math.log10(f / MIN_FREQ) + (lcg() - 0.5) * 4;\n\n  // Each harmonic contributes a narrow Gaussian bump in log-frequency space\n  let peakDb = -100;\n  for (const h of HARMONICS) {\n    const distance = (Math.log10(f) - Math.log10(h.freq)) / h.widthDecades;\n    peakDb = Math.max(peakDb, h.amplitudeDb - 4 * distance * distance);\n  }\n\n  // Combine floor and harmonics in the power domain, then back to dB\n  const powerSum = Math.pow(10, noiseFloorDb / 10) + Math.pow(10, peakDb / 10);\n  amplitude.push(Math.round(10 * Math.log10(powerSum) * 10) / 10);\n}\n\n// --- Chart (default-exported component — the harness mounts it) -------------\nexport default function Chart() {\n  const { width, height } = window.ANYPLOT_SIZE;\n  const titleHeight = 56;\n\n  return (\n    <div style={{ width, height, display: \"flex\", flexDirection: \"column\" }}>\n      <Typography\n        color=\"text.primary\"\n        sx={{\n          fontSize: 22,\n          fontWeight: 500,\n          height: titleHeight,\n          boxSizing: \"border-box\",\n          display: \"flex\",\n          alignItems: \"center\",\n          pl: 1,\n        }}\n      >\n        spectrum-basic · javascript · muix · anyplot.ai\n      </Typography>\n      <LineChart\n        width={width}\n        height={height - titleHeight}\n        skipAnimation\n        series={[\n          {\n            data: amplitude,\n            label: \"Amplitude\",\n            color: t.palette[0],\n            showMark: false,\n            curve: \"linear\",\n            area: true,\n          },\n        ]}\n        sx={{\n          \"& .MuiLineElement-root\": { strokeWidth: 2.5 },\n          \"& .MuiAreaElement-root\": { fillOpacity: 0.12 },\n        }}\n        xAxis={[\n          {\n            data: frequency,\n            scaleType: \"log\",\n            label: \"Frequency (Hz)\",\n            valueFormatter: (v) => (v >= 1000 ? `${Math.round(v / 100) / 10}k` : `${Math.round(v)}`),\n            labelStyle: { fontSize: 16 },\n            tickLabelStyle: { fontSize: 14 },\n          },\n        ]}\n        yAxis={[\n          {\n            label: \"Amplitude (dB)\",\n            labelStyle: { fontSize: 16 },\n            tickLabelStyle: { fontSize: 14 },\n            tickFontSize: 26,\n          },\n        ]}\n        grid={{ horizontal: true }}\n        margin={{ left: 130, right: 40, top: 20, bottom: 70 }}\n        slotProps={{ legend: { hidden: true } }}\n      >\n        <ChartsReferenceLine\n          x={FUNDAMENTAL_HZ}\n          label={`Fundamental · ${FUNDAMENTAL_HZ} Hz`}\n          labelAlign=\"end\"\n          lineStyle={{ stroke: t.amber, strokeDasharray: \"6 4\", strokeWidth: 1.5 }}\n          labelStyle={{ fill: t.amber, fontSize: 13 }}\n        />\n      </LineChart>\n    </div>\n  );\n}\n"}