{"spec_id":"spectrum-nmr","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// spectrum-nmr: NMR Spectrum (Nuclear Magnetic Resonance)\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 90/100 | Created: 2026-08-24\n//# anyplot-orientation: landscape\n// anyplot.ai\n// spectrum-nmr: NMR Spectrum (Nuclear Magnetic Resonance)\n// Library: Highcharts 12.6.0 | Node 22\n// License: Highcharts — commercial license, free for non-commercial use (highcharts.com/license)\n// Quality: pending | Created: 2026-08-24\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ---------------------------------------\n// Synthetic 1H NMR spectrum of ethanol (CH3-CH2-OH). Each signal is a\n// Lorentzian line shape; multiplets sum split component lines following the\n// n+1 rule (triplet 1:2:1 for CH3, quartet 1:3:3:1 for CH2).\nfunction lorentzian(shift, center, height, halfWidth) {\n  return (height * halfWidth * halfWidth) / ((shift - center) * (shift - center) + halfWidth * halfWidth);\n}\n\n// Tiny fixed-seed LCG for a touch of baseline noise (no seeded RNG in the browser)\nlet noiseSeed = 42;\nfunction nextNoise() {\n  noiseSeed = (noiseSeed * 1103515245 + 12345) & 0x7fffffff;\n  return noiseSeed / 0x7fffffff - 0.5;\n}\n\nconst minShift = -0.5;\nconst maxShift = 12.5;\nconst pointCount = 6000;\nconst step = (maxShift - minShift) / (pointCount - 1);\n\n// [center ppm, height, half-width ppm]\nconst lines = [\n  [0.0, 26, 0.008], // TMS reference singlet\n  [1.15, 20, 0.011], [1.2, 44, 0.011], [1.25, 20, 0.011], // CH3 triplet, 1:2:1\n  [2.6, 66, 0.026], // OH singlet, broadened (exchangeable proton)\n  [3.625, 13, 0.011], [3.675, 40, 0.011], [3.725, 40, 0.011], [3.775, 13, 0.011], // CH2 quartet, 1:3:3:1\n];\n\nconst spectrum = [];\nfor (let i = 0; i < pointCount; i++) {\n  const shift = minShift + i * step;\n  let intensity = 0;\n  for (const [center, height, halfWidth] of lines) {\n    intensity += lorentzian(shift, center, height, halfWidth);\n  }\n  intensity += nextNoise() * 0.5;\n  spectrum.push([Number(shift.toFixed(4)), Number(intensity.toFixed(3))]);\n}\n\nfunction apexNear(centerPpm, windowPpm) {\n  let best = -Infinity;\n  for (const [x, y] of spectrum) {\n    if (Math.abs(x - centerPpm) <= windowPpm) best = Math.max(best, y);\n  }\n  return best;\n}\n\nconst peakCallouts = [\n  { value: 0.0, window: 0.02, name: \"TMS 0.00\" },\n  { value: 1.2, window: 0.1, name: \"CH₃ 1.20 (t)\" },\n  { value: 2.6, window: 0.05, name: \"OH 2.60 (s)\" },\n  { value: 3.7, window: 0.15, name: \"CH₂ 3.70 (q)\" },\n].map((peak) => ({ x: peak.value, y: apexNear(peak.value, peak.window) + 7, name: peak.name }));\n\n// --- Chart -----------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"area\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"Ethanol · spectrum-nmr · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: \"Synthetic ¹H NMR spectrum (400 MHz, CDCl₃)\",\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    title: { text: \"Chemical Shift (δ, ppm)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    reversed: true,\n    min: minShift,\n    max: maxShift,\n    tickInterval: 1,\n    tickWidth: 0,\n    gridLineWidth: 0,\n    lineColor: t.inkSoft,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  yAxis: {\n    title: { text: \"Intensity (a.u.)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    labels: { enabled: false },\n    gridLineWidth: 0,\n    tickWidth: 0,\n    lineWidth: 1,\n    lineColor: t.inkSoft,\n    min: -3,\n  },\n  legend: { enabled: false },\n  tooltip: {\n    headerFormat: \"\",\n    pointFormat: \"δ {point.x:.2f} ppm — intensity {point.y:.1f}\",\n  },\n  plotOptions: {\n    series: { animation: false },\n    area: { lineWidth: 2.5, fillOpacity: 0.22, marker: { enabled: false }, threshold: 0 },\n  },\n  series: [\n    { name: \"Signal Intensity\", data: spectrum },\n    {\n      name: \"Peak Assignments\",\n      type: \"scatter\",\n      data: peakCallouts,\n      marker: { enabled: false },\n      enableMouseTracking: false,\n      dataLabels: {\n        enabled: true,\n        format: \"{point.name}\",\n        align: \"center\",\n        verticalAlign: \"bottom\",\n        style: { color: t.inkSoft, fontSize: \"13px\", fontWeight: \"500\", textOutline: \"none\" },\n      },\n    },\n  ],\n});\n"}