{"spec_id":"waveform-audio","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// waveform-audio: Audio Waveform Plot\n// Library: chartjs 4.4.7 | JavaScript 22.22.3\n// Quality: 92/100 | Created: 2026-06-03\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (deterministic in-memory) ------------------------------------------\n// Plucked-string model: overlapping harmonics with frequency-proportional decay\nconst sampleRate = 8820;\nconst duration = 2.0;\nconst f0 = 220; // A3 note — 220 cycles over 2 s gives a dense DAW-style view\nconst totalSamples = sampleRate * duration;\nconst waveData = new Array(totalSamples);\n\nfor (let i = 0; i < totalSamples; i++) {\n    const s = i / sampleRate;\n    const y =\n        0.58 * Math.exp(-s * 1.8) * Math.sin(2 * Math.PI * f0 * s) +\n        0.25 * Math.exp(-s * 4.0) * Math.sin(2 * Math.PI * f0 * 2 * s) +\n        0.12 * Math.exp(-s * 7.5) * Math.sin(2 * Math.PI * f0 * 3 * s) +\n        0.05 * Math.exp(-s * 13.0) * Math.sin(2 * Math.PI * f0 * 4 * s);\n    waveData[i] = { x: s, y };\n}\n\nconst zeroLine = [{ x: 0, y: 0 }, { x: duration, y: 0 }];\n\n// --- Mount -------------------------------------------------------------------\ndocument.getElementById(\"container\").style.backgroundColor = t.pageBg;\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Chart -------------------------------------------------------------------\nconst chartTitle = \"Plucked String · waveform-audio · javascript · chartjs · anyplot.ai\";\n\n// Decompose palette[0] (#009E73) into rgba for semi-transparent fill\nconst hex = t.palette[0];\nconst rgb = [\n    parseInt(hex.slice(1, 3), 16),\n    parseInt(hex.slice(3, 5), 16),\n    parseInt(hex.slice(5, 7), 16),\n].join(\", \");\n\nnew Chart(canvas, {\n    type: \"line\",\n    data: {\n        datasets: [\n            {\n                label: \"Amplitude\",\n                data: waveData,\n                parsing: false,\n                normalized: true,\n                borderColor: t.palette[0],\n                backgroundColor: `rgba(${rgb}, 0.3)`,\n                borderWidth: 1.2,\n                pointRadius: 0,\n                fill: \"origin\",\n                tension: 0,\n            },\n            {\n                label: \"Zero\",\n                data: zeroLine,\n                parsing: false,\n                borderColor: t.inkSoft,\n                borderDash: [6, 4],\n                borderWidth: 1,\n                pointRadius: 0,\n                fill: false,\n                tension: 0,\n            },\n        ],\n    },\n    options: {\n        responsive: true,\n        maintainAspectRatio: false,\n        animation: false,\n        plugins: {\n            title: {\n                display: true,\n                text: chartTitle,\n                color: t.ink,\n                font: { size: 22, weight: \"600\" },\n                padding: { top: 10, bottom: 18 },\n            },\n            legend: { display: false },\n        },\n        scales: {\n            x: {\n                type: \"linear\",\n                min: 0,\n                max: duration,\n                title: {\n                    display: true,\n                    text: \"Time (s)\",\n                    color: t.ink,\n                    font: { size: 18 },\n                },\n                ticks: {\n                    color: t.inkSoft,\n                    font: { size: 14 },\n                    callback: (v) => `${v.toFixed(1)}s`,\n                },\n                grid: { color: t.grid },\n            },\n            y: {\n                min: -1.0,\n                max: 1.0,\n                title: {\n                    display: true,\n                    text: \"Amplitude\",\n                    color: t.ink,\n                    font: { size: 18 },\n                },\n                ticks: {\n                    color: t.inkSoft,\n                    font: { size: 14 },\n                    stepSize: 0.5,\n                },\n                grid: { color: t.grid },\n            },\n        },\n    },\n});\n"}