AirString Studio 是一个运行在浏览器中的双手手势虚拟吉他。打开网页并授权摄像头后,用户可以在镜像画面的左侧选择和弦,通过右手“握拳后张开”完成拨弦,无需安装客户端或连接外部乐器。
项目基于 MediaPipe Hand Landmarker、Web Audio API、React 与 TypeScript 构建,界面使用 Tailwind CSS 与 shadcn/ui 风格的 Radix UI 组件。摄像头画面和手部关键点均在浏览器本地处理,不会由本应用上传;模型、WASM 运行时和字体也随站点一起发布,不依赖境外 CDN。
- 双手同时识别:按照镜像画面区域分配左右手职责,避免依赖容易翻转的 handedness 标签。
- 六个常用和弦:支持
C、G、Am、F、Em、Dm,使用对应的吉他开放和弦音高。 - 稳定的手势选择:滑动投票与置信度阈值共同减少手势跳变。
- 明确的拨弦动作:右手只有从闭合手掌变为张开手掌时才会触发,不会因上下移动误触。
- 两种演奏方式:支持扫弦和分解和弦,可调节速度、音量并开启自动分解。
- 实时视觉反馈:默认显示手部关键点,拨弦时展示当前和弦名称。
- 跟弹练习:内置三组原创和弦练习,提供当前进度和下一和弦提示。
- 中英文界面:可在页面顶部即时切换语言。
- 响应式布局:适配桌面和移动端浏览器。
- 识别调试面板:可查看 FPS、推理耗时、置信度、手势和右手状态。
摄像头预览是镜像画面,区域以用户在屏幕中看到的位置为准:
- 画面左侧:选择和弦。
- 画面右侧:控制拨弦。
| 手势编号 | 手势 | 和弦 |
|---|---|---|
| 1 | 食指 | C |
| 2 | 食指 + 中指 | G |
| 3 | 食指 + 中指 + 无名指 | Am |
| 4 | 食指 + 中指 + 无名指 + 小指 | F |
| 5 | 五指张开 | Em |
| 6 | 拇指 + 小指 | Dm |
三指手势允许拇指因掌心朝向产生轻微误判,因此掌心或手背朝向摄像头时都能正常使用。
- 在画面右侧握拳。
- 张开手掌。
- 每次“闭合 → 张开”触发一次拨弦。
右手的位置移动不会触发声音。触发后存在短暂冷却时间,以避免同一个动作被连续识别多次。
- Node.js 22 或更高版本
- pnpm 10 或更高版本
- 支持摄像头和 WebGL 的现代浏览器,推荐 Chrome 或 Edge
- 摄像头权限需要
localhost或 HTTPS 安全环境
pnpm install
pnpm dev开发服务器启动后,打开终端显示的本地地址,通常为:
http://localhost:5173
点击“开始演奏”并允许浏览器访问摄像头。演奏过程中可点击画面底部的“停止演奏”关闭摄像头和手势识别。
# 启动开发服务器
pnpm dev
# 运行全部测试
pnpm test
# ESLint 检查
pnpm lint
# TypeScript 类型检查
pnpm typecheck
# 构建生产版本
pnpm build
# 本地预览生产构建
pnpm preview生产文件会输出到 dist/ 目录。
- React 19
- TypeScript(严格模式)
- Vite 6
- Tailwind CSS 3
- shadcn/ui 组件架构(Radix UI、CVA、Tailwind Merge)
- MediaPipe Tasks Vision / Hand Landmarker
- Web Audio API + Meta Open Sound 尼龙吉他采样(CC0)
- Web Audio API
- Lucide React
- Vitest 与 Testing Library
- ESLint 与 Prettier
src/
├── components/ # 相机、和弦、练习和教程界面
├── config/ # 手势识别与 MediaPipe 配置
├── hooks/ # 摄像头、音频和手部追踪 Hooks
├── i18n/ # 中文与英文文案
├── lib/
│ ├── audio/ # 吉他音色与 Web Audio 调度
│ ├── mediapipe/ # 手势、左右区域与拨弦识别
│ └── music/ # 和弦定义与练习数据
├── App.tsx # 主应用状态与功能编排
└── styles.css # Tailwind 入口与少量全局基础规则
public/mediapipe/
├── models/ # 本地 Hand Landmarker 模型
└── wasm/ # 本地 MediaPipe WASM 运行时
public/audio/guitar/ # 本地尼龙吉他 OGG 采样
应用优先加载 public/audio/guitar/ 中的 17 个真实尼龙吉他采样,并按照六根吉他的实际弦位映射到开放和弦。相同琴弦再次触发时会自然停止上一声,避免不真实的无限叠音;采样加载失败时才会使用内置合成音色兜底。
采样来自 Meta Open Sound 的 Meta Nylon Guitar Vel01Finger 层,使用 CC0 1.0 公共领域许可。项目仅保留当前六组和弦实际用到的音高,并以 OGG 格式随站点本地部署,运行时不依赖第三方音频 CDN。
手势稳定帧数、置信度、冷却时间和推理帧率位于:
src/config/gesture.ts
默认推理上限为 30 FPS。MediaPipe 使用 GPU delegate,并通过 import.meta.env.BASE_URL 从本站的 public/mediapipe/ 加载 WASM 运行时与官方 Hand Landmarker 模型,因此同时兼容根路径部署和 GitHub Pages 的 /air-string/ 子路径。
模型与 WASM 会使生产包增加约 41 MB。部署时请完整上传 dist/mediapipe/,不要只上传 JavaScript 和 CSS 文件。
仓库中的 hand_landmarker.task SHA-256 为 fbc2a30080c3c557093b5ddfc334698132eb341044ccee322ccf8bcf3607cde1,升级模型时应同步更新并重新验证该值。
应用会在页面空闲时提前初始化 Hand Landmarker,并使用 Service Worker 长期缓存实际用到的模型与 WASM。首次访问仍需要下载资源,后续访问会直接使用本地缓存。
在右侧控制面板展开“识别调试”,可以查看:
- 实时 FPS
- 单帧推理耗时
- 左手识别置信度
- 原始手势与稳定结果
- 手指伸展状态
- 右手闭合/张开状态
调试面板为页面内嵌布局,不会覆盖摄像头或其他操作区域。
- 确认浏览器已经授予摄像头权限。
- 检查摄像头是否正在被其他应用占用。
- 线上访问时确认页面使用 HTTPS。
- 修改权限后刷新页面,再次点击“开始演奏”。
- 保持手掌完整进入画面,不要遮挡指尖和手腕。
- 使用均匀的正面光源,避免强烈逆光。
- 左右手分别放在画面的左右区域,中间留出一定距离。
- 将手与摄像头保持适中距离,避免手掌过小或超出画面。
- 必须先点击“开始演奏”,浏览器才允许创建音频上下文。
- 检查页面音量、系统音量以及浏览器标签页是否静音。
- Safari 用户可尝试再次点击和弦卡片以激活音频。
本应用直接在浏览器中完成摄像头帧和手部关键点分析。项目代码不包含上传、存储或发送摄像头画面的逻辑。MediaPipe 模型、WASM 运行时和界面字体均由当前站点本地提供,不会在运行时请求 Google Storage、jsDelivr 或 Google Fonts。
本项目采用 MIT License,详见 LICENSE。