{"spec_id":"feynman-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# feynman-basic: Feynman Diagram for Particle Interactions\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 93/100 | Created: 2026-06-03\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\nconst THEME     = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG   = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst PANEL_BG  = THEME == \"light\" ? colorant\"#F2F0E9\" : colorant\"#222220\"\nconst INK       = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT  = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst INK_MUTED = THEME == \"light\" ? colorant\"#6B6A63\" : colorant\"#A8A79F\"\n\nconst FERMION_COLOR = colorant\"#009E73\"  # brand green  (e-, e+, μ-, μ+, quarks)\nconst GLUON_COLOR   = colorant\"#C475FD\"  # lavender     (gluons / QCD)\nconst PHOTON_COLOR  = colorant\"#4467A3\"  # blue         (photons / EM bosons)\nconst SCALAR_COLOR  = colorant\"#BD8233\"  # ochre        (scalar bosons / Higgs)\n\n# ─── Makie @recipe: composable Feynman propagator plot types ─────────────────\n# Each recipe becomes a reusable, composable CairoMakie primitive — a Makie-\n# exclusive feature that makes the diagram grammar extensible and domain-specific.\n\n# Fermion propagator: solid line with a midpoint direction arrow\n@recipe(FermionProp, xs, ys, direction) do scene\n    Attributes(\n        color     = FERMION_COLOR,\n        linewidth = 2.5,\n        arrowsize = 14,\n    )\nend\n\nfunction Makie.plot!(fp::FermionProp)\n    xs        = fp[1][]\n    ys        = fp[2][]\n    direction = fp[3][]   # 1 = particle (forward), -1 = antiparticle (backward)\n    clr       = fp.color[]\n    lw        = fp.linewidth[]\n    arrsz     = fp.arrowsize[]\n\n    lines!(fp, xs, ys; color = clr, linewidth = lw)\n\n    n   = length(xs)\n    mid = n ÷ 2\n    dx  = xs[min(mid + 1, n)] - xs[max(mid - 1, 1)]\n    dy  = ys[min(mid + 1, n)] - ys[max(mid - 1, 1)]\n    len = sqrt(dx^2 + dy^2)\n    if len > 1e-9\n        arrows!(fp, [xs[mid]], [ys[mid]],\n                [direction * 0.001 * dx / len],\n                [direction * 0.001 * dy / len];\n                arrowsize = arrsz, color = clr, linewidth = 0)\n    end\n    fp\nend\n\n# Photon propagator: transverse sinusoidal wave\n@recipe(PhotonProp, x1, y1, x2, y2) do scene\n    Attributes(\n        color     = PHOTON_COLOR,\n        linewidth = 2.5,\n        n_waves   = 9,\n        amplitude = 0.038,\n    )\nend\n\nfunction Makie.plot!(pp::PhotonProp)\n    x1, y1 = pp[1][], pp[2][]\n    x2, y2 = pp[3][], pp[4][]\n    clr     = pp.color[]\n    lw      = pp.linewidth[]\n    nw      = pp.n_waves[]\n    amp     = pp.amplitude[]\n\n    dx  = x2 - x1; dy = y2 - y1\n    len = sqrt(dx^2 + dy^2)\n    nx  = -dy / len; ny = dx / len   # unit normal (transverse direction)\n\n    t    = LinRange(0.0, 1.0, 600)\n    xs_w = @. x1 + t * dx + amp * sin(nw * 2π * t) * nx\n    ys_w = @. y1 + t * dy + amp * sin(nw * 2π * t) * ny\n    lines!(pp, xs_w, ys_w; color = clr, linewidth = lw)\n    pp\nend\n\n# Gluon propagator: one-sided curly bumps via |sin| — visually distinct from photon\n@recipe(GluonProp, x1, y1, x2, y2) do scene\n    Attributes(\n        color     = GLUON_COLOR,\n        linewidth = 2.5,\n        n_loops   = 7,\n        amplitude = 0.048,\n    )\nend\n\nfunction Makie.plot!(gp::GluonProp)\n    x1, y1 = gp[1][], gp[2][]\n    x2, y2 = gp[3][], gp[4][]\n    clr     = gp.color[]\n    lw      = gp.linewidth[]\n    nl      = gp.n_loops[]\n    amp     = gp.amplitude[]\n\n    dx  = x2 - x1; dy = y2 - y1\n    len = sqrt(dx^2 + dy^2)\n    nx  = -dy / len; ny = dx / len\n\n    t    = LinRange(0.0, 1.0, 800)\n    xs_c = @. x1 + t * dx + amp * abs(sin(nl * π * t)) * nx\n    ys_c = @. y1 + t * dy + amp * abs(sin(nl * π * t)) * ny\n    lines!(gp, xs_c, ys_c; color = clr, linewidth = lw)\n    gp\nend\n\n# Scalar boson propagator: dashed line (Higgs, etc.)\n@recipe(ScalarProp, x1, y1, x2, y2) do scene\n    Attributes(\n        color     = SCALAR_COLOR,\n        linewidth = 2.5,\n        n_dashes  = 12,\n    )\nend\n\nfunction Makie.plot!(sp::ScalarProp)\n    x1, y1 = sp[1][], sp[2][]\n    x2, y2 = sp[3][], sp[4][]\n    clr     = sp.color[]\n    lw      = sp.linewidth[]\n    nd      = sp.n_dashes[]\n\n    xs_d = Float64[]\n    ys_d = Float64[]\n    for i in 0:(nd - 1)\n        t0 = i / nd\n        t1 = (i + 0.55) / nd\n        push!(xs_d, x1 + t0 * (x2 - x1), x1 + t1 * (x2 - x1), NaN)\n        push!(ys_d, y1 + t0 * (y2 - y1), y1 + t1 * (y2 - y1), NaN)\n    end\n    lines!(sp, xs_d, ys_d; color = clr, linewidth = lw)\n    sp\nend\n\n# ─── Figure: two-panel GridLayout ────────────────────────────────────────────\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\n# Title spans both columns\nLabel(fig[0, 1:2], \"feynman-basic · julia · makie · anyplot.ai\";\n      fontsize = 20, color = INK, halign = :center)\n\n# ─── Left panel: QED e+e- → μ+μ- s-channel diagram ──────────────────────────\nax = Axis(fig[1, 1];\n    backgroundcolor    = PAGE_BG,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    leftspinevisible   = false,\n    bottomspinevisible = false,\n    xgridvisible       = false,\n    ygridvisible       = false,\n    xticksvisible      = false,\n    yticksvisible      = false,\n    xticklabelsvisible = false,\n    yticklabelsvisible = false,\n)\nxlims!(ax, -0.06, 1.06)\nylims!(ax, 0.0, 1.0)\n\ntext!(ax, 0.50, 0.96;\n      text = \"e⁺e⁻ → μ⁺μ⁻  (QED s-channel)\",\n      fontsize = 16, color = INK_SOFT, align = (:center, :top))\n\n# Vertex positions\nv1x, v1y = 0.30, 0.50\nv2x, v2y = 0.70, 0.50\n\n# External leg endpoints\nem_x0, em_y0   = 0.02, 0.78   # e-  incoming top-left\nep_x0, ep_y0   = 0.02, 0.22   # e+  incoming bottom-left\nmum_x1, mum_y1 = 0.98, 0.78   # μ-  outgoing top-right\nmup_x1, mup_y1 = 0.98, 0.22   # μ+  outgoing bottom-right\n\nn_pts = 100\nfermionprop!(ax, LinRange(em_x0, v1x, n_pts), LinRange(em_y0, v1y, n_pts), 1)\nfermionprop!(ax, LinRange(ep_x0, v1x, n_pts), LinRange(ep_y0, v1y, n_pts), -1)\nfermionprop!(ax, LinRange(v2x, mum_x1, n_pts), LinRange(v2y, mum_y1, n_pts), 1)\nfermionprop!(ax, LinRange(v2x, mup_x1, n_pts), LinRange(v2y, mup_y1, n_pts), -1)\n\nphotonprop!(ax, v1x, v1y, v2x, v2y)\n\nscatter!(ax, [v1x, v2x], [v1y, v2y]; color = INK, markersize = 14, strokewidth = 0)\n\ntext!(ax, em_x0 - 0.01, em_y0 + 0.04;\n      text = \"e⁻\", fontsize = 20, color = FERMION_COLOR, align = (:right, :bottom))\ntext!(ax, ep_x0 - 0.01, ep_y0 - 0.04;\n      text = \"e⁺\", fontsize = 20, color = FERMION_COLOR, align = (:right, :top))\ntext!(ax, mum_x1 + 0.01, mum_y1 + 0.04;\n      text = \"μ⁻\", fontsize = 20, color = FERMION_COLOR, align = (:left, :bottom))\ntext!(ax, mup_x1 + 0.01, mup_y1 - 0.04;\n      text = \"μ⁺\", fontsize = 20, color = FERMION_COLOR, align = (:left, :top))\ntext!(ax, (v1x + v2x) / 2, v1y + 0.10;\n      text = \"γ* (virtual photon)\", fontsize = 17, color = PHOTON_COLOR,\n      align = (:center, :bottom))\n\narrows!(ax, [0.06], [0.07], [0.13], [0.0];\n        arrowsize = 10, color = INK_MUTED, linewidth = 1.5)\ntext!(ax, 0.125, 0.035;\n      text = \"time →\", fontsize = 15, color = INK_MUTED, align = (:center, :top))\n\n# ─── Right panel: Propagator type reference ───────────────────────────────────\nax2 = Axis(fig[1, 2];\n    backgroundcolor    = PANEL_BG,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    leftspinevisible   = false,\n    bottomspinevisible = false,\n    xgridvisible       = false,\n    ygridvisible       = false,\n    xticksvisible      = false,\n    yticksvisible      = false,\n    xticklabelsvisible = false,\n    yticklabelsvisible = false,\n)\nxlims!(ax2, 0.0, 1.0)\nylims!(ax2, 0.0, 1.0)\n\ntext!(ax2, 0.50, 0.95;\n      text = \"Propagator Types\", fontsize = 16, color = INK_SOFT, align = (:center, :top))\n\nprop_ys     = [0.73, 0.53, 0.33, 0.13]\nprop_labels = [\"Fermion  (e⁻, μ, q)\", \"Photon  (γ)\", \"Gluon  (g)\", \"Scalar  (H)\"]\nprop_colors = [FERMION_COLOR, PHOTON_COLOR, GLUON_COLOR, SCALAR_COLOR]\n\nfermionprop!(ax2, LinRange(0.06, 0.52, n_pts), fill(prop_ys[1], n_pts), 1;\n             color = FERMION_COLOR, arrowsize = 12)\nphotonprop!(ax2, 0.06, prop_ys[2], 0.52, prop_ys[2];\n            color = PHOTON_COLOR, n_waves = 7, amplitude = 0.035)\ngluonprop!(ax2, 0.06, prop_ys[3], 0.52, prop_ys[3];\n           color = GLUON_COLOR, n_loops = 5, amplitude = 0.04)\nscalarprop!(ax2, 0.06, prop_ys[4], 0.52, prop_ys[4];\n            color = SCALAR_COLOR, n_dashes = 10)\n\nfor (y, lbl, clr) in zip(prop_ys, prop_labels, prop_colors)\n    text!(ax2, 0.56, y; text = lbl, fontsize = 13, color = clr, align = (:left, :center))\nend\n\n# Column widths: 65% main diagram, 35% reference panel\ncolsize!(fig.layout, 1, Relative(0.65))\ncolsize!(fig.layout, 2, Relative(0.35))\n\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}