{"spec_id":"feynman-basic","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// feynman-basic: Feynman Diagram for Particle Interactions\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 92/100 | Created: 2026-08-20\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: e- + e+ -> gamma -> mu- + mu+ (QED annihilation / pair production) ---\n// Vertices are interaction points; propagators connect them (or connect a\n// vertex to an external incoming/outgoing leg). Coordinates are a plain\n// data-space grid — time runs left to right, as is conventional.\nconst V1 = { x: 2, y: 0 };\nconst V2 = { x: 4, y: 0 };\nconst V3 = { x: 9, y: 0 };\nconst V4 = { x: 11, y: 0 };\n\nconst legs = [\n  { from: { x: 0, y: 2.6 }, to: V1, style: \"straight\", color: t.palette[0],\n    label: \"e⁻\", align: \"left\", labelPos: { x: 0.4, y: 2.85 }, arrow: \"forward\" },\n  { from: { x: 0, y: -2.6 }, to: V1, style: \"straight\", color: t.palette[0],\n    label: \"e⁺\", align: \"left\", labelPos: { x: 0.4, y: -2.95 }, arrow: \"backward\" },\n  { from: V1, to: V2, style: \"wavy\", color: t.palette[1],\n    label: \"γ\", align: \"center\", labelPos: { x: 3, y: 0.7 }, arrow: null },\n  { from: V2, to: { x: 6, y: 2.6 }, style: \"straight\", color: t.palette[2],\n    label: \"μ⁻\", align: \"right\", labelPos: { x: 5.6, y: 2.85 }, arrow: \"forward\" },\n  { from: V2, to: { x: 6, y: -2.6 }, style: \"straight\", color: t.palette[2],\n    label: \"μ⁺\", align: \"right\", labelPos: { x: 5.6, y: -2.95 }, arrow: \"backward\" },\n  // --- Second vertex pair: gg -> H -> b b̄ (gluon fusion / Higgs decay) -------\n  { from: { x: 7, y: 2.6 }, to: V3, style: \"curly\", color: t.palette[3],\n    label: \"g\", align: \"left\", labelPos: { x: 7.4, y: 2.85 }, arrow: null },\n  { from: { x: 7, y: -2.6 }, to: V3, style: \"curly\", color: t.palette[3],\n    label: \"g\", align: \"left\", labelPos: { x: 7.4, y: -2.95 }, arrow: null },\n  { from: V3, to: V4, style: \"dashed\", color: t.palette[4],\n    label: \"H\", align: \"center\", labelPos: { x: 10, y: 0.7 }, arrow: null },\n  { from: V4, to: { x: 13, y: 2.6 }, style: \"straight\", color: t.palette[0],\n    label: \"b\", align: \"right\", labelPos: { x: 12.6, y: 2.85 }, arrow: \"forward\" },\n  { from: V4, to: { x: 13, y: -2.6 }, style: \"straight\", color: t.palette[0],\n    label: \"b̄\", align: \"right\", labelPos: { x: 12.6, y: -2.95 }, arrow: \"backward\" },\n];\n\n// --- Helpers -----------------------------------------------------------------\n\nfunction toPx(chart, point) {\n  return {\n    x: chart.xAxis[0].toPixels(point.x, false),\n    y: chart.yAxis[0].toPixels(point.y, false),\n  };\n}\n\nfunction straightPath(p1, p2) {\n  return [\"M\", p1.x, p1.y, \"L\", p2.x, p2.y];\n}\n\nfunction wavyPath(p1, p2, amplitude, wavelengths) {\n  const dx = p2.x - p1.x;\n  const dy = p2.y - p1.y;\n  const len = Math.sqrt(dx * dx + dy * dy);\n  const ux = dx / len;\n  const uy = dy / len;\n  const nx = -uy;\n  const ny = ux;\n  const steps = 120;\n  const path = [\"M\", p1.x, p1.y];\n  for (let i = 1; i <= steps; i++) {\n    const s = i / steps;\n    const offset = amplitude * Math.sin(2 * Math.PI * wavelengths * s);\n    path.push(\"L\", p1.x + ux * len * s + nx * offset, p1.y + uy * len * s + ny * offset);\n  }\n  return path;\n}\n\nfunction curlyPath(p1, p2, amplitude, loops) {\n  const dx = p2.x - p1.x;\n  const dy = p2.y - p1.y;\n  const len = Math.sqrt(dx * dx + dy * dy);\n  const ux = dx / len;\n  const uy = dy / len;\n  const nx = -uy;\n  const ny = ux;\n  const steps = 160;\n  const path = [\"M\", p1.x, p1.y];\n  for (let i = 1; i <= steps; i++) {\n    const s = i / steps;\n    const along = len * s - amplitude * 0.6 * (1 - Math.cos(2 * Math.PI * loops * s));\n    const normal = amplitude * Math.sin(2 * Math.PI * loops * s);\n    path.push(\"L\", p1.x + ux * along + nx * normal, p1.y + uy * along + ny * normal);\n  }\n  return path;\n}\n\n// Arrowhead centred on (cx, cy), pointing along `angle` (radians).\nfunction arrowPath(cx, cy, angle, size) {\n  const half = size * 0.55;\n  const tipX = cx + size * 0.6 * Math.cos(angle);\n  const tipY = cy + size * 0.6 * Math.sin(angle);\n  const baseX = cx - size * 0.4 * Math.cos(angle);\n  const baseY = cy - size * 0.4 * Math.sin(angle);\n  const perp = angle + Math.PI / 2;\n  const leftX = baseX + half * Math.cos(perp);\n  const leftY = baseY + half * Math.sin(perp);\n  const rightX = baseX - half * Math.cos(perp);\n  const rightY = baseY - half * Math.sin(perp);\n  return [\"M\", tipX, tipY, \"L\", leftX, leftY, \"L\", rightX, rightY, \"Z\"];\n}\n\nfunction drawDiagram(chart) {\n  const renderer = chart.renderer;\n  const group = renderer.g(\"feynman-diagram\").add();\n\n  legs.forEach((leg) => {\n    const p1 = toPx(chart, leg.from);\n    const p2 = toPx(chart, leg.to);\n\n    let path;\n    if (leg.style === \"wavy\") path = wavyPath(p1, p2, 14, 5);\n    else if (leg.style === \"curly\") path = curlyPath(p1, p2, 12, 6);\n    else path = straightPath(p1, p2);\n\n    const attrs = { stroke: leg.color, \"stroke-width\": 3, fill: \"none\", \"stroke-linejoin\": \"round\" };\n    if (leg.style === \"dashed\") attrs[\"stroke-dasharray\"] = \"10,7\";\n    renderer.path(path).attr(attrs).add(group);\n\n    if (leg.arrow) {\n      const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\n      let angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);\n      if (leg.arrow === \"backward\") angle += Math.PI;\n      renderer.path(arrowPath(mid.x, mid.y, angle, 20))\n        .attr({ fill: leg.color, stroke: \"none\" })\n        .add(group);\n    }\n\n    const labelPx = toPx(chart, leg.labelPos);\n    renderer.text(leg.label, labelPx.x, labelPx.y)\n      .attr({ align: leg.align })\n      .css({ color: leg.color, fontSize: \"20px\", fontWeight: \"600\" })\n      .add(group);\n  });\n\n  [V1, V2, V3, V4].forEach((vertex) => {\n    const p = toPx(chart, vertex);\n    renderer.circle(p.x, p.y, 8).attr({ fill: t.ink, stroke: \"none\" }).add(group);\n  });\n}\n\n// --- Chart ---------------------------------------------------------------\n// Axes are used purely as the data-to-pixel coordinate system (hidden line,\n// ticks, gridlines) — the diagram itself is drawn with the SVG renderer in\n// the `load` event so lines/arrows can follow arbitrary particle-line\n// geometry (straight with arrowheads, sine-wave photon) that no built-in\n// series type expresses.\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"line\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n    events: {\n      load: function () {\n        drawDiagram(this);\n      },\n    },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"feynman-basic · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  xAxis: {\n    min: -0.5,\n    max: 13.5,\n    startOnTick: false,\n    endOnTick: false,\n    lineWidth: 0,\n    tickLength: 0,\n    gridLineWidth: 0,\n    labels: { enabled: false },\n    title: { text: \"time →\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n  },\n  yAxis: {\n    min: -3.6,\n    max: 3.6,\n    startOnTick: false,\n    endOnTick: false,\n    lineWidth: 0,\n    tickLength: 0,\n    gridLineWidth: 0,\n    labels: { enabled: false },\n    title: { text: null },\n  },\n  legend: {\n    align: \"right\",\n    verticalAlign: \"middle\",\n    layout: \"vertical\",\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  tooltip: { enabled: false },\n  plotOptions: { series: { animation: false, enableMouseTracking: false, marker: { enabled: false } } },\n  series: [\n    { name: \"Electron / positron / b-quark (fermion)\", color: t.palette[0], lineWidth: 3, data: [], showInLegend: true },\n    { name: \"Photon (γ, wavy)\", color: t.palette[1], lineWidth: 3, data: [], showInLegend: true },\n    { name: \"Muon / antimuon (fermion)\", color: t.palette[2], lineWidth: 3, data: [], showInLegend: true },\n    { name: \"Gluon (g, curly)\", color: t.palette[3], lineWidth: 3, data: [], showInLegend: true },\n    { name: \"Higgs boson (H, dashed)\", color: t.palette[4], lineWidth: 3, dashStyle: \"Dash\", data: [], showInLegend: true },\n  ],\n});\n"}