{"spec_id":"line-retention-cohort","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// line-retention-cohort: User Retention Curve by Cohort\n// Library: chartjs 4.4.7 | JavaScript 22.22.3\n// Quality: 90/100 | Created: 2026-06-20\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Data — weekly retention for 5 monthly signup cohorts (deterministic)\nconst weeks = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];\n\nconst cohorts = [\n  { label: \"Jan 2025\", size: 1245, data: [100, 72, 58, 50, 45, 41, 37, 34, 31, 29, 27, 24, 21] },\n  { label: \"Feb 2025\", size: 1387, data: [100, 74, 61, 53, 48, 44, 40, 37, 34, 32, 30, 27, 24] },\n  { label: \"Mar 2025\", size: 1521, data: [100, 77, 64, 56, 51, 47, 43, 40, 37, 35, 33, 30, 27] },\n  { label: \"Apr 2025\", size: 1683, data: [100, 80, 68, 60, 55, 51, 47, 44, 41, 38, 36, 33, 30] },\n  { label: \"May 2025\", size: 1892, data: [100, 83, 72, 64, 59, 55, 51, 48, 45, 42, 40, 37, 34] },\n];\n\n// Thicker lines for newer cohorts to emphasize recent improvements\nconst lineWidths = [2, 2.5, 3, 3.5, 4];\n\nconst datasets = [\n  ...cohorts.map((cohort, i) => ({\n    label: `${cohort.label} (n=${cohort.size.toLocaleString()})`,\n    data: cohort.data,\n    borderColor: t.palette[i],\n    borderWidth: lineWidths[i],\n    pointRadius: 3,\n    pointBackgroundColor: t.palette[i],\n    fill: false,\n    tension: 0.3,\n  })),\n  // 20% retention benchmark reference line\n  {\n    label: \"20% Benchmark\",\n    data: weeks.map(() => 20),\n    borderColor: t.inkSoft,\n    borderWidth: 1.5,\n    borderDash: [8, 4],\n    pointRadius: 0,\n    fill: false,\n    tension: 0,\n  },\n];\n\n// Mount\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// Chart\nnew Chart(canvas, {\n  type: \"line\",\n  data: {\n    labels: weeks,\n    datasets,\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: {\n      title: {\n        display: true,\n        text: \"line-retention-cohort · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 22, weight: \"500\" },\n        padding: { bottom: 16 },\n      },\n      legend: {\n        labels: {\n          color: t.ink,\n          font: { size: 14 },\n          usePointStyle: true,\n          padding: 16,\n        },\n      },\n    },\n    scales: {\n      x: {\n        ticks: { color: t.inkSoft, font: { size: 13 } },\n        grid: { color: t.grid },\n        title: {\n          display: true,\n          text: \"Weeks Since Signup\",\n          color: t.ink,\n          font: { size: 15 },\n          padding: { top: 8 },\n        },\n      },\n      y: {\n        min: 0,\n        max: 100,\n        ticks: {\n          color: t.inkSoft,\n          font: { size: 13 },\n          callback: (v) => v + \"%\",\n          stepSize: 20,\n        },\n        grid: { color: t.grid },\n        title: {\n          display: true,\n          text: \"Retention Rate (%)\",\n          color: t.ink,\n          font: { size: 15 },\n          padding: { bottom: 8 },\n        },\n      },\n    },\n  },\n});\n"}