SuperAPI AI 工具集

audio-and-haptics-feedback

通用与其它

查看项目

更新于 10-18 18:04

技能介绍

用途

本技能用于在 Expo 应用中构建音效(SFX)、音乐与触觉反馈层。它把音频与触觉封装在端口(port)之后:每个反馈音效由字面量配方(SoundRecipe)合成,并通过 AudioPort 之后的唯一环境 AudioContext 播放;每个触觉脉冲来自固定提示表,在 iOS 与 Android 上通过 HapticsPort 播放,受用户偏好控制并做节流。技能同时构建端口、提示表、音效库以及两个用于验证的检查器。

主要能力与规则

  • 单一引擎、端口隔离:只有 src/services/audio/audio-api-audio-adapter.ts 导入 react-native-audio-api,只有 src/services/haptics/expo-haptics-adapter.ts 导入 expo-haptics;反馈层不导入媒体播放器,Vibration 不出现在反馈层或视图中。测试使用 createFakeAudio() / createFakeHaptics()。
  • 精确锁定 react-native-audio-api 版本,并通过 AUDIO_API_PLUGIN 覆盖全部五个插件默认值(iosBackgroundMode: false、androidPermissions: []、androidForegroundService: false、disableFFmpeg: true、disableStaticExternalLibs: true)。
  • 单一 AudioContext,在 setAudioSessionOptions({ iosCategory: 'ambient' }) 之后于适配器中创建;Android 上不获取音频焦点(observeAudioInterruptions(true) 仅在 Platform.OS === 'ios' 下调用)。
  • 每个音效是字面量 SoundRecipe,需通过 recipeProblems 校验(有限、峰值 0.05–0.9、首样本 < 0.05、末样本 < 0.01、后续层淡入至少 1 ms、时长 10–1500 ms、音乐最长 30 s)。反馈层不做流式播放、不使用 URL 音频。
  • 音效库与 id:使用 kebab-case 名词描述发生的事件;ui. 保留给 UI_SOUNDS;每个功能或游戏的音效库位于 <owner>/sounds/<owner>-sounds.ts,命名为 <OWNER>_SOUNDS,经测试后在根布局用 composeSoundBank 组合一次(冲突时抛错)。
  • 语音策略:三类增益(sfx 与 ui 跟随音效,music 跟随音乐)、音量平方、50 ms 渐变、最多 8 个重叠语音、同一音效每 30 ms 最多一次(或 minIntervalMs,最多 1000)、语音作为音频时钟上的区间,由 cancelPending 释放。
  • 音乐默认关闭,从不 activelyReclaimSession;当 hasMusic(bank) 为 false 时隐藏所有音乐控件。
  • 反馈从 JS 事件触发:功能提示表由模型播放(playCue)、画布轨道提示按音频时钟调度、UI 时刻(playUiFeedback)或排空的模拟事件;绝不从视图自身处理器、模拟、'worklet' 模块或逐帧触发。视图(src/ui、功能屏幕或组件)绝不调用 audio.play、playCue 或 playUiFeedback。
  • 在根布局挂载一次 useAudioLifecycle;上下文仅在应用活跃且无全屏播放时运行;iOS 中断会挂起,仅在生命周期仍希望运行时恢复。每次 JS 重载前 await audio.dispose(),或使用注入的 beforeReload 钩子,或注明 // audio-dispose-exempt: <reason>。
  • 触觉在两个平台遵循提示表(iOS 反馈生成器;Android performAndroidHapticsAsync 常量,含 API 30 表与旧版表),仅在用户偏好开启时、间隔至少 40 ms、每次调用在适配器内以 .catch(() => undefined) 结束;iPad 上 isSupported 为 false。视图仅使用 selection(开关、选择器)。
  • 应用级时刻通过 UI_FEEDBACK(默认 toggle、success、error);按钮默认静音,若应用添加点击时刻则渲染 <PressFeedbackProvider playsSound onPress={...}>。
  • 不预先添加麦克风用途字符串;仅当 App Store 上传报告 ITMS-90683 时设置 iosMicrophonePermission。

使用方式

工作流按任务选择步骤:新建反馈层走步骤 2–6;为功能或游戏添加音效走步骤 7–9;调音走步骤 8–9;升级库走步骤 10;始终以步骤 11 收尾。

  1. 阅读 references/audio-engine.md 与 references/haptics.md。
  2. 复制模板:templates/src/services/audio/(含 synth/)、templates/src/services/haptics/、templates/src/services/feedback/、templates/src/services/test-hooks/recording-feedback.ts、templates/src/config/audio-plugin.ts、templates/__mocks__/react-native-audio-api.ts、templates/contracts/audio-feedback.json(含 schema)。
  3. 安装:npx expo install expo-haptics 与 npm install --save-exact react-native-audio-api@0.13.6;在 app.config.ts 的 plugins 中加入 AUDIO_API_PLUGIN;确认 .gitignore 忽略 reports/。
  4. 接线组合根:在 Services、createDeviceServices 与 createTestServices 中接入 audio 与 haptics;在根布局的启动初始化器中 services.audio.load(composeSoundBank(...)),并挂载一次 useAudioLifecycle(...);参考 examples/root-layout-wiring.tsx。
  5. 接线时刻:在开关处理器中 playUiFeedback(services, 'toggle'),在请求动作结束时 'success' / 'error'。
  6. 规划音效:阅读 references/sound-design.md,写出事件 → 音效 → 触觉表。
  7. 测试先行编写音效库与提示表:复制 templates/src/features/__FEATURE__/,替换占位符,为每个音效写一个字面量配方,从模型用 playCue 播放每一行,将音效库加入 composeSoundBank,运行 npx prettier --write src/features/<feature> 与 npx jest src/features/<feature> --ci --selectProjects unit 直到通过。
  8. 渲染并交付试听:node ${CLAUDE_SKILL_DIR}/scripts/check-sound-banks.mjs . --wav-dir reports/sfx,修复每个 FAIL,按 examples/listening-checklist.md 列出试听清单。
  9. 升级 react-native-audio-api:遵循 audio-engine.md 中的 “Before any bump”,然后在 contracts/audio-feedback.json 中设置 audioApiVersion。
  10. 运行检查直到两者打印 RESULT: PASS:node ${CLAUDE_SKILL_DIR}/scripts/check-sound-banks.mjs . 与 node ${CLAUDE_SKILL_DIR}/scripts/check-audio-haptics.mjs .;然后运行 npx jest src/services src/features/<feature> --ci --selectProjects unit android。

适用场景

适用于使用 Expo 的 React Native 应用,需要为功能或游戏添加音效、音乐或触觉反馈,或需要调音、升级音频库、建立统一反馈层时。也适用于仅需触觉的应用(只复制 haptics/ 目录,检查器会注明音频规则不适用)。

限制

  • 反馈层不做流式播放、不使用 URL 音频;每个仓库中的录音文件必须在契约中列出许可证与来源。
  • 音乐默认关闭,且库无法判断用户自身音频是否在播放,因此应用不会未经请求覆盖播放。
  • 触觉在 iPad 上 isSupported 为 false;Android 上使用 impactAsync 会直接驱动 Vibrator,应使用 performAndroidHapticsAsync。
  • 绿色门禁只证明音效干净,不证明正确;需渲染 WAV 预览并在真实 iPhone 与 Android 手机上人工试听,且不阻塞流程。
  • 代理无法听见声音,模拟器没有触觉引擎。
  • 不得通过提高 MAX_VOICES、降低 40 ms 节流或放宽门禁来通过检查。
  • 测试中不得导入 expo-haptics 或 react-native-audio-api,应使用 jest.mock + jest.requireMock 与 fake。
  • 具体收费、价格、平台支持范围等未在资料中提供。