我们要构建的"MP3-Visualization"应用包含四个功能:
本节展示真实的对话全过程。每轮对话后,你会看到 AI 做了什么、文件发生了什么变化。
你的输入:
项目骨架已创建。现在请帮我在 index.html 中添加一个简单的界面布局——左侧是播放控制区,右侧是可视化画布。不需要花哨,能看就行。
AI 做了什么:
index.html,添加左右分栏布局style.css 中添加基础样式app.js 中初始化 Canvas 和 AudioContext文件变化:
index.html 中多了一个两栏结构:
<div id="app">
<div id="controls">
<input type="file" id="fileInput" accept="audio/mp3">
<button id="playBtn">播放</button>
<input type="range" id="volumeSlider" min="0" max="1" step="0.01">
</div>
<canvas id="visualizer"></canvas>
</div>
你在这一轮的决策: 布局方案。你可能没有意识到,但你做了一个设计选择:左控制右画布。这个选择会影响后面所有功能的摆放位置。如果你之后发现"左边放控件空间不够",可以随时调整——AI 会帮你改。
你的输入:
现在添加一个实时频谱可视化效果。用户选择 MP3 文件后,画布上显示随音乐跳动的频谱柱状图。
AI 做了什么:
requestAnimationFrame 动画循环关键代码片段——这是 AI 写的最核心的部分:
const audioCtx = new AudioContext();
const analyser = audioCtx.createAnalyser();
analyser.fftSize = 256;
function drawSpectrum() {
requestAnimationFrame(drawSpectrum);
const dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(dataArray);
ctx.clearRect(0, 0, canvas.width, canvas.height);
const barWidth = canvas.width / dataArray.length;
dataArray.forEach((value, i) => {
const barHeight = (value / 255) * canvas.height;
ctx.fillStyle = `hsl(${i * 4}, 70%, 50%)`;
ctx.fillRect(i * barWidth, canvas.height - barHeight, barWidth - 1, barHeight);
});
}
你可能想问的问题:
这段代码中每一行都在做什么?如果你好奇,可以问 AI:
"解释一下 drawSpectrum 函数中每一行是做什么的。"
AI 会逐行解释:requestAnimationFrame 创建动画循环、getByteFrequencyData 获取当前帧的频谱数据、fillRect 在画布上绘制柱状条。
你不需要现在理解每一行。但如果你愿意,每轮对话后花 30 秒问问 AI "这段代码的关键逻辑是什么",你会逐渐积累对代码的理解。
优化方向:
柱状图跑起来之后,你可以继续优化。比如:
"柱状图的颜色用 HSL 色环过渡,从青色到紫色到红色。"
AI 会修改 fillStyle 的计算逻辑,颜色从低频到高频自然过渡。
"柱子之间留一点间隙,看起来更清晰。"
AI 会在 fillRect 的宽度参数上减 1 或 2 像素。
你的输入:
我想加一个歌词功能。用户在左侧文本框中输入歌词,每行前面标注时间戳(格式 mm:ss),播放时高亮显示当前时间对应的歌词行。
AI 做了什么:
关键代码——歌词解析器:
function parseLyrics(text) {
const lines = text.split('\n');
return lines.map(line => {
const match = line.match(/\[(\d{2}):(\d{2})\](.*)/);
if (match) {
return {
time: parseInt(match[1]) * 60 + parseInt(match[2]),
text: match[3].trim()
};
}
return null;
}).filter(l => l !== null);
}
你的"创意贡献":
AI 生成的歌词解析器默认按行匹配。你可以提出一个改进:
"如果歌词时间戳不是严格递增的,能否按最接近当前时间的行匹配?"
这个需求 AI 不会自己想到——因为这是你的使用场景决定的。这就是你在 Vibe Coding 中真正贡献的价值。
AI 会修改匹配逻辑:不再是"当前时间等于某行的时间戳才高亮",而是"在已排序的歌词行中,找到最接近当前时间的行"。即使时间戳不严格递增,也能正确工作。
你的输入:
最后加一个录制功能。点击"录制"按钮,将 Canvas 上的可视化效果和音频一起录制成 WebM 视频文件。
AI 做了什么:
MediaRecorder 捕获 Canvas 流AudioContext.createMediaStreamDestination() 合并音频关键代码——录制核心:
let mediaRecorder;
let recordedChunks = [];
function startRecording() {
const canvasStream = canvas.captureStream(30);
const audioDest = audioCtx.createMediaStreamDestination();
audioSource.connect(audioDest);
const combinedStream = new MediaStream([
...canvasStream.getVideoTracks(),
...audioDest.stream.getAudioTracks()
]);
mediaRecorder = new MediaRecorder(combinedStream);
recordedChunks = [];
mediaRecorder.ondataavailable = (e) => recordedChunks.push(e.data);
mediaRecorder.onstop = () => {
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
// 创建下载链接
};
mediaRecorder.start();
}
你可能遇到并需要修复的问题:
"录制下来的视频没有声音。"
这是一个很常见的问题。AI 会分析发现 audio 元素没有正确地连接到 MediaStreamDestination,导致录制时只捕获了画面没有捕获声音。修复后视频就正常了。
随着功能增加,你可能想管理多个音频文件:
"添加一个播放列表功能。用户选择的 MP3 文件显示在列表中,可以点击切换,当前播放的歌曲高亮显示。"
AI 做了什么:
你在这个阶段的思考:
"播放列表中的歌曲播放完后,自动播放下一首。"
AI 会添加 audio.onended 事件监听,自动播放下一个。
"播放列表支持拖拽排序。"
AI 实现 HTML5 拖拽 API。不过你会发现在纯 HTML5 项目中实现拖拽排序比想象中复杂——AI 生成的代码可能第一次不够完美,需要几轮调整。
"添加键盘快捷键:空格键播放/暂停,左右方向键快进/后退 5 秒,上下方向键调节音量。"
AI 做了什么:
这个功能的代码量不大(大约 30 行),但对用户体验的提升很明显——用户不需要用鼠标点击按钮,键盘操作更快捷。
"添加一个保存配置的功能。用户调整的参数(音量、可视化模式、颜色方案)在刷新页面后不会丢失。"
AI 做了什么:
localStorage 保存用户偏好function saveConfig() {
const config = {
volume: volumeSlider.value,
visualMode: currentMode,
colorScheme: currentColorScheme
};
localStorage.setItem('mp3-visualizer-config', JSON.stringify(config));
}
function loadConfig() {
const saved = localStorage.getItem('mp3-visualizer-config');
if (saved) {
const config = JSON.parse(saved);
volumeSlider.value = config.volume;
currentMode = config.visualMode;
// 恢复各配置项
}
}
在实际操作中,你的对话可能像这样:
你:我想做一个 MP3 音频可视化应用,HTML5 项目。
AI:好的,我创建了 index.html、style.css 和 app.js……
你:布局改成左右分栏,左边控件右边画布。
AI:已修改布局……
你:频谱柱状图太普通了,改成圆形辐射状效果。
AI:已改成圆形辐射状可视化……
你:录制出来的视频没有声音。
AI:检查发现 audio 元素没有连接到 MediaStream,修复了……
你:歌词高亮延迟了半秒,调整一下。
AI:将时间戳匹配逻辑从逐行扫描改为二分查找……
你:加一个播放列表,支持多文件管理和自动下一首。
AI:已添加播放列表功能……
你:界面右上角加一个模式切换按钮,点击在三种可视化效果间切换。
AI:已添加模式切换……
你:添加键盘快捷键,空格播放/暂停,左右方向键快进后退。
AI:已添加键盘快捷键……
你:刷新页面后设置都丢了,用 localStorage 保存用户配置。
AI:已添加配置持久化……
注意看——上面每一行对话都对应一个真实的开发决策。有些是设计决策(布局、视觉效果),有些是功能决策(录制、歌词、播放列表),有些是调试(声音问题、延迟问题),有些是体验优化(快捷键、配置保存)。你的角色是"拍板的人",AI 是"执行的人"。
认知一:你的指令越具体,AI 第一次就越接近你的目标。
比较两个指令:
❌ "帮我搞一下可视化。"——AI 不知道你要什么效果、什么风格、什么交互方式。
✅ "在右侧画布上添加频谱柱状图效果,柱状条用渐变色,从青色(低频)过渡到紫色(中频)再到红色(高频)。"——AI 生成的代码第一次就接近你的目标。
你不一定每次都能给出具体指令——有时候你确实不知道自己想要什么。没关系,先让 AI 给一个默认方案,你说"改成另一种风格"就可以。
认知二:先让 AI 给出默认方案,再迭代优化,比一开始就追求完美高效得多。
这条规则不仅适用于代码,也适用于 UI、交互方式、技术选型。AI 的第一次输出通常是"安全的选择"——主流的技术方案、常见的 UI 模式。你先接受这个默认方案,然后基于实际的体验感受去改进。
认知三:有些需求 AI 不会自己想到,需要你提出来。
播放列表自动切歌、键盘快捷键、刷新后保持配置——这些"体验细节"AI 不会主动做,因为第一个版本的核心功能才是它的优先关注点。你在使用过程中的"不爽"——"为什么每次都要重新调音量"——就是最宝贵的产品反馈来源。把它变成一句话告诉 AI,它就帮你改了。
对 Claude Code 说:
"我想复现这个 MP3 可视化项目。帮我创建一个包含音频播放、频谱可视化和录制功能的应用,不要求歌词功能。请逐步实现,每一步完成后让我确认再继续。"
进阶练习:
完成基础功能后,提出一个自定义需求:比如"在播放列表上方添加一个搜索框,可以过滤列表中的文件名"。观察 AI 如何理解"搜索框 + 过滤"这个新需求并集成到现有界面中。注意:这个需求在之前的对话中没有出现过——是你自己提出的新功能。