{"spec_id":"line-parametric","library":"muix","language":"javascript","code":"// anyplot.ai\n// line-parametric: Parametric Curve Plot\n// Library: muix 7.29.1 | JavaScript 22.22.3\n// Quality: 86/100 | Created: 2026-06-20\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// Linear interpolation between two hex colors (Imprint sequential gradient)\nfunction lerpColor(hex1: string, hex2: string, alpha: number): string {\n  const p = (h: string, o: number) => parseInt(h.slice(o, o + 2), 16);\n  const r = Math.round(p(hex1, 1) + (p(hex2, 1) - p(hex1, 1)) * alpha);\n  const g = Math.round(p(hex1, 3) + (p(hex2, 3) - p(hex1, 3)) * alpha);\n  const b = Math.round(p(hex1, 5) + (p(hex2, 5) - p(hex1, 5)) * alpha);\n  return `#${r.toString(16).padStart(2, \"0\")}${g.toString(16).padStart(2, \"0\")}${b.toString(16).padStart(2, \"0\")}`;\n}\n\n// --- Data (deterministic, in-memory) ----------------------------------------\nconst N = 800;\nconst SEGS = 20;\nconst PI2 = 2 * Math.PI;\n\n// Lissajous figure: x = sin(3t + π/4), y = sin(2t), t ∈ [0, 2π]\nconst lissajousPoints = Array.from({ length: N }, (_, i) => {\n  const ti = (i / (N - 1)) * PI2;\n  return { x: Math.sin(3 * ti + Math.PI / 4), y: Math.sin(2 * ti), id: i };\n});\n\n// Archimedean spiral: x = t·cos(t), y = t·sin(t), t ∈ [0, 4π]\nconst spiralPoints = Array.from({ length: N }, (_, i) => {\n  const ti = (i / (N - 1)) * 2 * PI2;\n  return { x: ti * Math.cos(ti), y: ti * Math.sin(ti), id: i };\n});\n\n// Segment each curve into SEGS color bands for Imprint seq gradient\n// #009E73 (brand green, t=start) → #4467A3 (blue, t=end)\nconst SEQ_START = \"#009E73\";\nconst SEQ_END = \"#4467A3\";\n\nfunction buildGradientSeries(points: { x: number; y: number; id: number }[]) {\n  const segLen = Math.ceil(points.length / SEGS);\n  return Array.from({ length: SEGS }, (_, s) => ({\n    data: points.slice(s * segLen, Math.min((s + 1) * segLen + 1, points.length)),\n    color: lerpColor(SEQ_START, SEQ_END, s / (SEGS - 1)),\n    label: \"\",\n    markerSize: 3.5,\n    id: `seg-${s}`,\n  }));\n}\n\nconst lissajousSeries = buildGradientSeries(lissajousPoints);\nconst spiralSeries = buildGradientSeries(spiralPoints);\n\n// --- Chart ------------------------------------------------------------------\nexport default function Chart() {\n  const { width, height } = window.ANYPLOT_SIZE;\n  const half = Math.floor((width - 60) / 2);\n  const chartH = height - 100;\n  // Square chart enforces equal aspect ratio when both axes cover the same numeric range.\n  // Margins top=25, bottom=50, left=55, right=20 → plot area = (side-75) × (side-75).\n  const chartSide = Math.min(half, chartH);\n\n  const axisLabel = { fill: t.ink, fontSize: 13 };\n  const axisTick = { fill: t.inkSoft, fontSize: 11 };\n\n  return (\n    <Box\n      sx={{\n        width,\n        height,\n        bgcolor: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        px: 2,\n        pt: 1.5,\n        boxSizing: \"border-box\",\n      }}\n    >\n      <Typography\n        sx={{\n          color: t.ink,\n          fontSize: 20,\n          fontWeight: 500,\n          textAlign: \"center\",\n          mb: 1,\n          letterSpacing: 0,\n        }}\n      >\n        line-parametric · javascript · muix · anyplot.ai\n      </Typography>\n\n      <Box sx={{ display: \"flex\", gap: 2, flex: 1, justifyContent: \"center\", alignItems: \"flex-start\" }}>\n        {/* Lissajous figure — equal aspect ratio: square chart, same axis range, balanced margins */}\n        <Box sx={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\" }}>\n          <Typography sx={{ color: t.inkSoft, fontSize: 14, mb: 0.5 }}>\n            Lissajous Figure &mdash; x = sin(3t + π/4), y = sin(2t), t ∈ [0, 2π]\n          </Typography>\n          <ScatterChart\n            width={chartSide}\n            height={chartSide}\n            skipAnimation\n            series={lissajousSeries}\n            grid={{ horizontal: false, vertical: false }}\n            xAxis={[{\n              label: \"x(t)\",\n              labelStyle: axisLabel,\n              tickLabelStyle: axisTick,\n              min: -1.25,\n              max: 1.25,\n            }]}\n            yAxis={[{\n              label: \"y(t)\",\n              labelStyle: axisLabel,\n              tickLabelStyle: axisTick,\n              min: -1.25,\n              max: 1.25,\n            }]}\n            margin={{ top: 25, bottom: 50, left: 55, right: 20 }}\n            slotProps={{ legend: { hidden: true } }}\n          />\n        </Box>\n\n        {/* Archimedean spiral — equal aspect ratio: square chart, symmetric axis range */}\n        <Box sx={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\" }}>\n          <Typography sx={{ color: t.inkSoft, fontSize: 14, mb: 0.5 }}>\n            Archimedean Spiral &mdash; x = t·cos(t), y = t·sin(t), t ∈ [0, 4π]\n          </Typography>\n          <ScatterChart\n            width={chartSide}\n            height={chartSide}\n            skipAnimation\n            series={spiralSeries}\n            grid={{ horizontal: false, vertical: false }}\n            xAxis={[{\n              label: \"x(t)\",\n              labelStyle: axisLabel,\n              tickLabelStyle: axisTick,\n              min: -14,\n              max: 14,\n            }]}\n            yAxis={[{\n              label: \"y(t)\",\n              labelStyle: axisLabel,\n              tickLabelStyle: axisTick,\n              min: -14,\n              max: 14,\n            }]}\n            margin={{ top: 25, bottom: 50, left: 55, right: 20 }}\n            slotProps={{ legend: { hidden: true } }}\n          />\n        </Box>\n      </Box>\n\n      <Typography sx={{ color: t.inkSoft, fontSize: 13, textAlign: \"center\", mt: 0.5 }}>\n        Color encodes direction of traversal — green (t = start) → blue (t = end)\n      </Typography>\n    </Box>\n  );\n}\n"}