{"spec_id":"phase-diagram","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// phase-diagram: Phase Diagram (State Space Plot)\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 88/100 | Created: 2026-09-05\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: damped pendulum, dθ/dt vs θ, from four initial displacements -----\n// θ'' + 2·ζ·ω·θ' + ω²·θ = 0, integrated with RK4 so every trajectory spirals\n// deterministically toward the equilibrium at the origin.\nconst OMEGA = 1.6; // natural frequency (rad/s)\nconst ZETA = 0.18; // damping ratio (underdamped -> spiral, not straight decay)\nconst DT = 0.02;\nconst STEPS = 700;\n\nfunction derivative(theta, omega_dot) {\n  return [omega_dot, -2 * ZETA * OMEGA * omega_dot - OMEGA * OMEGA * theta];\n}\n\nfunction integrateTrajectory(theta0, omegaDot0) {\n  const points = [];\n  let theta = theta0;\n  let omegaDot = omegaDot0;\n  for (let i = 0; i <= STEPS; i++) {\n    points.push([theta, omegaDot]);\n    const [k1t, k1o] = derivative(theta, omegaDot);\n    const [k2t, k2o] = derivative(theta + (DT / 2) * k1t, omegaDot + (DT / 2) * k1o);\n    const [k3t, k3o] = derivative(theta + (DT / 2) * k2t, omegaDot + (DT / 2) * k2o);\n    const [k4t, k4o] = derivative(theta + DT * k3t, omegaDot + DT * k3o);\n    theta += (DT / 6) * (k1t + 2 * k2t + 2 * k3t + k4t);\n    omegaDot += (DT / 6) * (k1o + 2 * k2o + 2 * k3o + k4o);\n  }\n  return points;\n}\n\n// Four initial displacements (radians) and angular velocities (rad/s), each\n// spiraling into the same stable fixed point at the origin.\nconst initialConditions = [\n  { theta0: 1.2, omegaDot0: 0.0, label: \"Released from 1.2 rad\" },\n  { theta0: -1.0, omegaDot0: 1.4, label: \"Pushed at −1.0 rad\" },\n  { theta0: 0.3, omegaDot0: 2.2, label: \"Flicked at 0.3 rad\" },\n  { theta0: -1.5, omegaDot0: -1.1, label: \"Pushed at −1.5 rad\" },\n];\n\nconst trajectories = initialConditions.map((ic) => ({\n  ...ic,\n  points: integrateTrajectory(ic.theta0, ic.omegaDot0),\n}));\n\nfunction hexToRgba(hex, alpha) {\n  const h = hex.replace(\"#\", \"\");\n  const r = parseInt(h.substring(0, 2), 16);\n  const g = parseInt(h.substring(2, 4), 16);\n  const b = parseInt(h.substring(4, 6), 16);\n  return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n// Each trajectory is drawn as a run of short line segments whose opacity rises\n// from faint (t=0, far from equilibrium) to solid (final points, at rest) —\n// a time-evolution cue that follows the actual path order, unlike a bounding-box\n// SVG gradient which would fade by spatial position instead of by time.\nconst SEGMENTS = 10;\nfunction fadedTrailSegments(traj, baseColor) {\n  const pts = traj.points;\n  const segLen = Math.ceil(pts.length / SEGMENTS);\n  const segments = [];\n  for (let s = 0; s < SEGMENTS; s++) {\n    const start = s * segLen;\n    if (start >= pts.length - 1) break;\n    const end = Math.min(pts.length - 1, start + segLen);\n    const alpha = 0.22 + (0.78 * s) / (SEGMENTS - 1);\n    segments.push({\n      name: traj.label,\n      type: \"line\",\n      data: pts.slice(start, end + 1),\n      color: hexToRgba(baseColor, alpha),\n      lineWidth: 2.5,\n      marker: { enabled: false },\n      showInLegend: s === SEGMENTS - 1,\n    });\n  }\n  return segments;\n}\n\n// --- Chart -------------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"line\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"phase-diagram · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: \"Damped pendulum: four initial conditions spiraling into the same equilibrium\",\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    title: { text: \"Angular Displacement θ (rad)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineColor: t.grid,\n    gridLineWidth: 1,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    plotLines: [{ value: 0, color: t.inkSoft, width: 1, zIndex: 2 }],\n  },\n  yAxis: {\n    title: { text: \"Angular Velocity dθ/dt (rad/s)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineColor: t.grid,\n    gridLineWidth: 1,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    plotLines: [{ value: 0, color: t.inkSoft, width: 1, zIndex: 2 }],\n  },\n  legend: {\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  tooltip: {\n    headerFormat: \"<b>{series.name}</b><br/>\",\n    pointFormat: \"θ = {point.x:.2f} rad, dθ/dt = {point.y:.2f} rad/s\",\n  },\n  plotOptions: {\n    series: { animation: false },\n  },\n  series: [\n    {\n      name: \"Equilibrium halo\",\n      type: \"scatter\",\n      data: [[0, 0]],\n      color: hexToRgba(t.ink, 0.08),\n      marker: { symbol: \"circle\", radius: 34, lineWidth: 0 },\n      enableMouseTracking: false,\n      showInLegend: false,\n      zIndex: 0,\n    },\n    ...trajectories.flatMap((traj, i) => fadedTrailSegments(traj, t.palette[i])),\n    ...trajectories.map((traj, i) => ({\n      name: `${traj.label} start`,\n      type: \"scatter\",\n      data: [traj.points[0]],\n      color: t.palette[i],\n      marker: { symbol: \"circle\", radius: 6, lineWidth: 1.5, lineColor: t.pageBg },\n      enableMouseTracking: false,\n      showInLegend: false,\n      zIndex: 4,\n    })),\n    {\n      name: \"Equilibrium\",\n      type: \"scatter\",\n      data: [[0, 0]],\n      color: t.ink,\n      marker: { symbol: \"diamond\", radius: 8, lineWidth: 1.5, lineColor: t.pageBg },\n      zIndex: 5,\n    },\n  ],\n});\n"}