# @audiowave/react 中文文档

规范地址：https://npmcn.com/package/%40audiowave/react/

版本：0\.6\.2
npm 元数据更新时间：2025-10-31T07:23:29.861Z
中文译文更新时间：2026-11-07T04:36:08.527Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40audiowave/react
原文对照：https://npmcn.com/package/%40audiowave/react/?lang=original
项目主页：https://github.com/teomyth/audiowave#readme
源码仓库：https://github.com/teomyth/audiowave

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：342 kB，30 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：react \>=16\.8\.0，react-dom \>=16\.8\.0
- 首次发布：2025-07-26T11:42:01.515Z
- 最新版本发布：2025-10-31T07:23:29.644Z
- 近 30 天下载量：784096（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：8（近 12 个月 0 个）

## 中文简介

反射音频可视化组件

## 安装

```sh
npm install @audiowave/react
```

也可以使用：`pnpm add @audiowave/react`、`yarn add @audiowave/react`、`bun add @audiowave/react`

## README

# @ audiowave/反应

**用于实时音频可视化的轻量级 React 组件**

## 启发和关键差异

这个项目的灵感来自 [反应-视听器](https://github.com/Wolfy64/react-audio-visualize) 但采取不同、更有重点的办法:

**是什么让我们不同:**

-   **只可视化** - 没有内置播放或记录功能
-   **无控制按钮** - 纯可视化组件,无UI控制
-   **轻巧** - 有重点特性集的最小捆绑大小
-   **简单整合** - 投放现有音频应用程序而不发生冲突
-   **弹性** - 使用你提供的任何音频源

**适合这些情景:**

-   **现有音频应用程序** - 在已经处理音频的应用程序中添加可视化
-   **记录软件** - 可视化麦克风输入而不发生音频冲突
-   **音乐播放器** - 在音频/视频播放中添加波形
-   **自定义音频工作流程** - 与任何音频来源或处理管道相结合
-   **轻量级项目** - 最小捆绑大小,只需要可视化

## 安装

```bash
npm install @audiowave/react
```

## 快速启动

**用麦克风输入的基本用途 :**

```tsx
import { AudioWave, useMediaAudio } from '@audiowave/react';
import { useRef, useState, useMemo, useCallback } from 'react';

export default function App() {
  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);
  const [isRecording, setIsRecording] = useState(false);

  // AudioWave handles visualization, you control the audio source
  // Note: For dynamic audio sources, memoize the options object (see Important Usage Notes)
  const handleError = useCallback((error: Error) => {
    console.error('Audio error:', error);
  }, []);

  const audioOptions = useMemo(() => ({
    source: mediaStream,
    onError: handleError,
  }), [mediaStream, handleError]);

  const { source, error } = useMediaAudio(audioOptions);
  const audioWaveRef = useRef<AudioWaveController>(null);

  const startRecording = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    setMediaStream(stream);
    setIsRecording(true);
  };

  const stopRecording = () => {
    mediaStream?.getTracks().forEach(track => track.stop());
    setMediaStream(null);
    setIsRecording(false);
  };

  return (
    <div>
      {error && <div>Error: {error.message}</div>}
      <AudioWave ref={audioWaveRef} source={source} height={100} />

      {/* You provide the controls - AudioWave just visualizes */}
      <button onClick={isRecording ? stopRecording : startRecording}>
        {isRecording ? 'Stop Recording' : 'Start Recording'}
      </button>

      {/* Optional: Control visualization display */}
      <button onClick={() => audioWaveRef.current?.pause()}>Pause Waveform</button>
      <button onClick={() => audioWaveRef.current?.resume()}>Resume Waveform</button>
      <button onClick={() => audioWaveRef.current?.clear()}>Clear Waveform</button>
    </div>
  );
}
```

**工作与任何音频源 :**

```tsx
// With audio file
const audioElement = useRef<HTMLAudioElement>(null);
const { source } = useAudioSource({ source: audioElement.current });

// With video file
const videoElement = useRef<HTMLVideoElement>(null);
const { source } = useAudioSource({ source: videoElement.current });

// With Web Audio API nodes
const { source } = useAudioSource({ source: audioNode });

// With custom audio data (Electron, Node.js, etc.)
const { source } = useCustomAudio();
```

## API 参考

### 音频窗口组件

主要可视化组件 - 纯显示,无音频控制.

```tsx
<AudioWave
  // === AUDIO SOURCE ===
  source={source}            // AudioSource from useAudioSource

  // === DIMENSIONS ===
  width="100%"               // Component width (string | number)
  height={200}               // Component height in pixels

  // === VISUAL STYLING ===
  backgroundColor="transparent" // Background color
  barColor="#ffffff"         // Primary bar color
  secondaryBarColor="#5e5e5e" // Secondary/inactive bar color
  barWidth={2}               // Width of each frequency bar
  gap={1}                    // Gap between bars in pixels
  rounded={0}                // Border radius for rounded bars

  // === BORDER STYLING ===
  showBorder={false}         // Show border around visualization
  borderColor="#333333"      // Border color
  borderWidth={1}            // Border width in pixels
  borderRadius={0}           // Border radius for rounded corners

  // === AMPLITUDE CALCULATION ===
  amplitudeMode="peak"       // Amplitude calculation: 'peak' | 'rms' | 'adaptive'

  // === ANIMATION & RENDERING ===
  speed={3}                  // Animation speed (1-6, higher = slower)
  animateCurrentPick={true}  // Enable smooth bar transitions
  fullscreen={false}         // Fill entire parent container
  onlyActive={false}         // Show visualization only when active
  gain={1.0}                 // Audio gain multiplier (0.1-10.0, default: 1.0)

  // === STATE CONTROL ===
  isPaused={false}           // Pause visualization (freeze display)

  // === ADVANCED CUSTOMIZATION ===
  customRenderer={(context) => {
    // Custom rendering function for advanced visualizations
    // context: { canvas, audioData, width, height, ... }
  }}

  // === PLACEHOLDER CONTENT ===
  placeholder={<div>No audio source</div>} // Custom placeholder content
  showPlaceholderBackground={true}         // Show background in placeholder state

  // === CSS CLASSES ===
  className="my-waveform"    // CSS class for main container
  canvasClassName="my-canvas" // CSS class for canvas element

  // === CALLBACKS ===
  onStateChange={(state) => console.log('State:', state)} // State change callback
  onRenderStart={() => console.log('Rendering started')}  // Render start callback
  onRenderStop={() => console.log('Rendering stopped')}   // Render stop callback
  onError={(error) => console.error('Error:', error)}     // Error callback
/>
```

#### 基本主张

**音频来源 :**

-   `source` - 音频来源于 `useMediaAudio` 或者说 `useCustomAudio` 钩子(视觉需要)

**尺寸 :**

-   `width` - 组件宽度,支持CSS单元和数字(默认: `"100%"`(中文(简体) )
-   `height` - 组件高度,以像素计(默认值: `200`(中文(简体) )

**视觉造型 :**

-   `backgroundColor` - 背景颜色( 默认 ): `"transparent"`(中文(简体) )
-   `barColor` - 活动音频栏的主要颜色( 默认 ): `"#ffffff"`(中文(简体) )
-   `secondaryBarColor` - 非活动/后行的颜色(默认值 : `"#5e5e5e"`(中文(简体) )
-   `barWidth` - 每个频率栏以像素表示的宽度( 默认 ): `2`(中文(简体) )
-   `gap` - 像素条之间的间隔( 默认值 : `1`(中文(简体) )
-   `rounded` - 四舍五入条的边框半径(默认值: `0`(中文(简体) )

#### 高级道具

**边框样式 :**

-   `showBorder` - 显示可视化区域的边框( 默认 ): `false`(中文(简体) )
-   `borderColor` - 边框颜色( 默认 ): `"#333333"`(中文(简体) )
-   `borderWidth` - 以像素为单位的边框宽度( 默认值 : `1`(中文(简体) )
-   `borderRadius` - 圆角的边框半径( 默认 ): `0`(中文(简体) )

**动画和渲染 :**

-   `speed` - 动画速度从 1 - 6 起,较高数字更慢(默认 : `3`(中文(简体) )
-   `animateCurrentPick` - 启用平滑条过渡(默认: `true`(中文(简体) )
-   `fullscreen` - 装入整个母容器(默认值 : `false`(中文(简体) )
-   `onlyActive` - 仅在音频活动时显示可视化( 默认 ): `false`(中文(简体) )

**国家管制:**

-   `isPaused` - 在不影响音频的情况下暂停可视化显示(默认: `false`(中文(简体) )

**高级自定义 :**

-   `customRenderer` - 高级可视化的自定义渲染功能
-   `placeholder` - 自定义反应组件,在没有音频源时显示
-   `showPlaceholderBackground` - 是否在占位符状态下显示背景

**CSS 类 :**

-   `className` - 主容器的CSS级
-   `canvasClassName` - 帆布元素的CSS类

**事件召回 :**

-   `onStateChange` - 当视觉状态发生变化时调用
-   `onRenderStart` - 开始渲染时打电话
-   `onRenderStop` - 停止渲染时打电话
-   `onError` - 调用 翻译错误

### 使用MediaAudio Hook( 建议)

将媒体来源转换为可视化数据。 这是大多数使用案例的主要钩子.

```tsx
const { source, error } = useMediaAudio({
  source: mediaStream  // MediaStream | HTMLAudioElement | HTMLVideoElement | AudioNode
});
```

> **重要内容:** 当使用懒惰装入的音频源时(开始于 `null`),您必须记住选项对象以防止闪烁。 见 [重要使用说明](https://npmcn.com/package/%40audiowave/react/#readme-important-usage-notes) 详细情况.

**支持的来源 :**

-   `MediaStream` - 麦克风、录音软件
-   `HTMLAudioElement` - 音频文件
-   `HTMLVideoElement` - 视频文件
-   `AudioNode` - 网络音频 API 节点

**回返情况:**

-   `source` - AudioWave 组件的音频来源实例
-   `error` - 任何处理错误(无效)

### 使用Audio Source Hook( 语言)

> **说明:** `useAudioSource` 是用于 `useMediaAudio` 为后向相容性维护。 新项目应使用 `useMediaAudio`。 。 。 .

### 专用钩子

为了更好的类型安全和方便,您可以使用专门的钩:

```tsx
// For microphone or recording software
const { source, error } = useMediaStreamSource(mediaStream);

// For audio/video files
const { source, error } = useMediaElementSource(audioElement);

// For Web Audio API nodes
const { source, error } = useAudioNodeSource(audioNode);

// For custom audio data (Electron, Node.js, etc.)
const { source } = useCustomAudio({ provider: myProvider });
```

### 使用 CustomAudio Hook 软件

对于需要提供自定义音频数据(Electron Apps、Node.js音频处理、自定义音频管道)的高级使用案例,请使用 `useCustomAudio` 与自定义提供者连接 :

```tsx
import { useCustomAudio } from '@audiowave/react';
import { useMemo } from 'react';

function CustomAudioApp() {
  // Create audio data provider
  const audioProvider = useMemo(() => ({
    onAudioData: (callback: (data: Uint8Array) => void) => {
      // Your audio data subscription logic
      const unsubscribe = yourAudioSource.subscribe(callback);
      return unsubscribe; // Return cleanup function
    },
    onAudioError: (callback: (error: string) => void) => {
      // Optional error handling
      const unsubscribe = yourAudioSource.onError(callback);
      return unsubscribe;
    }
  }), []);

  const { source, error } = useCustomAudio({
    provider: audioProvider,
    deviceId: 'default'
  });

  return (
    <div>
      {error && <div>Error: {error}</div>}
      <AudioWave source={source} height={120} />
    </div>
  );
}
```

**参数:**

-   `provider` - 音频数据实施(需要)
-   `deviceId` - 设备标识符(可选,默认:"默认")

**回返情况:**

-   `source` - AudioWave 组件的音频来源实例
-   `status` - 当前状态 : “ idle ” ; “ 活动 ” ; “ 暂停 ”
-   `error` - 如果有错误消息
-   `isActive` - 布尔表示音频是否活动
-   `clearError` - 清除错误状态的函数

**音频数据格式 :**

-   `Uint8Array` 数值在幅度 \[0, 255\]
-   128 代表静默( 中值)
-   128以上值表示正振幅
-   128以下值表示负振幅
-   阵列长度应该符合您想要的可视化分辨率

## 电子融合指南

用于电子应用, 使用 `useCustomAudio` 与本地音频处理的自定义提供者:

### 最佳做法:主要进程音频处理

最佳性能的主要进程中处理音频 :

**主要进程`main.js`:**

```typescript
import { AudioProcessor } from '@audiowave/core';
import { ipcMain } from 'electron';

class ElectronAudioCapture {
  private audioProcessor: AudioProcessor;

  constructor() {
    this.audioProcessor = new AudioProcessor({
      bufferSize: 1024,
      skipInitialFrames: 2,
      inputBitsPerSample: 32,  // naudiodon uses 32-bit
      inputChannels: 2,        // stereo input
    });

    this.setupAudioCapture();
  }

  private setupAudioCapture() {
    // Setup your audio capture (naudiodon, etc.)
    audioCapture.on('data', (buffer: Buffer) => {
      // Process audio in main process
      const result = this.audioProcessor.process(buffer);

      if (result) {
        // Send processed data to renderer
        mainWindow.webContents.send('audio-data', result.timeDomainData);
      }
    });
  }
}

// IPC handlers
ipcMain.handle('start-audio-capture', async () => {
  // Start audio capture logic
});

ipcMain.handle('stop-audio-capture', async () => {
  // Stop audio capture logic
});
```

**渲染器进程( R)`renderer.tsx`:**

```tsx
import { useCustomAudio } from '@audiowave/react';
import { useMemo } from 'react';

function ElectronAudioApp() {
  // Create provider for Electron IPC communication
  const electronProvider = useMemo(() => ({
    onAudioData: (callback: (data: Uint8Array) => void) => {
      const handleAudioData = (_event: any, audioData: Uint8Array) => {
        callback(audioData);
      };

      window.electronAPI.onAudioData(handleAudioData);

      return () => {
        window.electronAPI.removeAudioDataListener?.(handleAudioData);
      };
    },
    onAudioError: (callback: (error: string) => void) => {
      const handleError = (_event: any, error: string) => {
        callback(error);
      };

      window.electronAPI.onAudioError?.(handleError);

      return () => {
        window.electronAPI.removeAudioErrorListener?.(handleError);
      };
    }
  }), []);

  const { source, error } = useCustomAudio({
    provider: electronProvider,
    deviceId: 'default'
  });

  const startCapture = () => {
    window.electronAPI.startAudioCapture();
  };

  const stopCapture = () => {
    window.electronAPI.stopAudioCapture();
  };

  return (
    <div>
      {error && <div>Error: {error}</div>}
      <AudioWave source={source} height={120} />
      <button onClick={startCapture}>Start</button>
      <button onClick={stopCapture}>Stop</button>
    </div>
  );
}
```

**预装脚本( P)`preload.js`:**

```typescript
import { contextBridge, ipcRenderer } from 'electron';

contextBridge.exposeInMainWorld('electronAPI', {
  startAudioCapture: () => ipcRenderer.invoke('start-audio-capture'),
  stopAudioCapture: () => ipcRenderer.invoke('stop-audio-capture'),
  onAudioData: (callback: (event: any, data: Uint8Array) => void) => {
    ipcRenderer.on('audio-data', callback);
  },
  onAudioError: (callback: (event: any, error: string) => void) => {
    ipcRenderer.on('audio-error', callback);
  },
  removeAudioDataListener: (callback: Function) => {
    ipcRenderer.removeListener('audio-data', callback);
  },
  removeAudioErrorListener: (callback: Function) => {
    ipcRenderer.removeListener('audio-error', callback);
  }
});
```

**这种办法的好处:**

-   最小数据传输的优化性能
-   维持UI响应能力
-   多个窗口的单一处理实例

## 可视化控制

AudioWave为可视化显示提供了简单的控制(而不是音频本身):

### 使用参考文献( 模拟)

```tsx
const audioWaveRef = useRef<AudioWaveController>(null);

// Basic visualization controls
audioWaveRef.current?.pause();  // Freeze display
audioWaveRef.current?.resume(); // Resume display
audioWaveRef.current?.clear();  // Clear waveform data

// State inspection methods
const isPaused = audioWaveRef.current?.isPaused(); // Check if paused
const state = audioWaveRef.current?.getState();    // Get current state: 'idle' | 'visualizing' | 'paused'
const audioData = audioWaveRef.current?.getAudioData(); // Get current audio data (Uint8Array)
```

#### 音频窗口控制器方法

**控制方法:**

-   `pause()` - 暂停可视化(冻结波形显示)
-   `resume()` - 从暂停状态恢复可视化
-   `clear()` - 清除所有波形数据并重置显示

**国家方法:**

-   `isPaused()` - 返回布尔表示是否暂停可视化
-   `getState()` - 返回当前状态: `'idle'` | `'visualizing'` | `'paused'`
-   `getAudioData()` - 返回当前音频数据为 Uint8Array

### 使用道具( 声明)

```tsx
const [isPaused, setIsPaused] = useState(false);

<AudioWave
  source={source}
  isPaused={isPaused}  // Control via props
/>
```

**重要内容:** 这些控件只影响可视化显示,而不是你的音频源.

## 高度计算模式

AudioWave支持三种不同的振幅计算方法,以满足不同的可视化需要:

### 峰值模式( 默认)

```tsx
<AudioWave source={source} amplitudeMode="peak" />
```

-   **最好还是**:通用可视化,音乐,动态内容
-   **行为**: 使用频率数据的峰值振幅值
-   **特征**:高响应度,清晰显示所有音频峰值
-   **向后兼容**: 默认模式, 维护已有行为

### RMS 模式( 实际声音)

```tsx
<AudioWave source={source} amplitudeMode="rms" />
```

-   **最好还是**:语音分析,广播音频,感知出响比对
-   **行为**: 根平方计算代表人类如何看待高音
-   **特征**: 更平滑的可视化, 更好地代表所感知的音量
-   **安静的环境**: 通过平稳的噪音地面过渡而增强
    -   范围 1-9: 有指数缩放的静态信号
    -   范围 10+: 有对数缩放的可听信号
    -   自然基线(1)为环境噪声下限

### 适应模式( 动态缩放)

```tsx
<AudioWave source={source} amplitudeMode="adaptive" />
```

-   **最好还是**: 音频级别不同,自动增益调整,内容混合
-   **行为**: 根据最近的音频级别动态调整缩放
-   **特征**: 自动补偿静音或高音源
-   **使用大小写**: 当音频级别差异很大或无法预测时

### 模式切换示例

```tsx
import { useState } from 'react';
import { AudioWave, useAudioSource } from '@audiowave/react';

function AmplitudeModeDemo() {
  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);
  const [amplitudeMode, setAmplitudeMode] = useState<'peak' | 'rms' | 'adaptive'>('peak');

  const { source } = useAudioSource({ source: mediaStream });

  return (
    <div>
      <AudioWave
        source={source}
        amplitudeMode={amplitudeMode}
        height={120}
        barWidth={2}
        gap={1}
      />

      <div>
        <label>Amplitude Mode:</label>
        <select
          value={amplitudeMode}
          onChange={(e) => setAmplitudeMode(e.target.value as any)}
        >
          <option value="peak">Peak (Default)</option>
          <option value="rms">RMS (Perceptual)</option>
          <option value="adaptive">Adaptive (Auto-scaling)</option>
        </select>
      </div>
    </div>
  );
}
```

## 最佳做法

### 处理错误

```tsx
const { source, error } = useAudioSource({ source: mediaStream });

if (error) {
  return <div>Visualization error: {error.message}</div>;
}
```

### 重要使用说明

#### 懒惰装入音频源( 适当功能需要)

当您的音频源启动时 `null` 后设定(常见于用户启动的情景),您 **必须** 记住 `useAudioSource` 选项。 没有这个,可视化将不断闪烁并重启,使其无法使用:

**\- 这会导致闪烁:**

```tsx
function MyAudioApp() {
  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);

  // This creates a new options object on every render!
  const { source } = useMediaAudio({
    source: mediaStream,
    onError: (error) => console.error('Audio error:', error)
  });

  // ... rest of component
}
```

**QQ CORRECT - 纪念选项对象 :**

```tsx
function MyAudioApp() {
  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);

  // Step 1: Memoize the onError callback
  const handleAudioError = useCallback((error: Error) => {
    console.error('Audio error:', error);
  }, []);

  // Step 2: Memoize the entire options object
  const audioSourceOptions = useMemo(() => ({
    source: mediaStream,
    onError: handleAudioError,
  }), [mediaStream, handleAudioError]);

  // Step 3: Use the memoized options
  const { source } = useMediaAudio(audioSourceOptions);

  const startRecording = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    setMediaStream(stream); // This triggers re-render with new source
  };

  return (
    <div>
      <button onClick={startRecording}>Start Recording</button>
      <AudioWave source={source} />
    </div>
  );
}
```

**为什么需要这样做?**

-   每个参数都会创建一个新选项对象 `{ source: mediaStream, onError: ... }`
-   `useMediaAudio` 视此为"变化"并重新初始化音频处理
-   这导致可视化反复闪烁并重启,使其无法使用
-   这不是性能问题 这是正常运行的功能要求

**快速引用 - 复制此模式 :**

```tsx
// Always use this pattern for lazy-loaded audio sources
const handleError = useCallback((error: Error) => {
  console.error('Audio error:', error);
}, []);

const options = useMemo(() => ({
  source: yourAudioSource, // MediaStream | HTMLAudioElement | etc.
  onError: handleError,
}), [yourAudioSource, handleError]);

const { source } = useMediaAudio(options);
```

### 性能优化

#### 纪念组件道具

```tsx
// Memoize AudioWave props for better performance
const audioWaveProps = useMemo(() => ({
  source,
  height: 200,
  barWidth: 2,
  gap: 1,
  backgroundColor: 'transparent',
  barColor: '#ffffff'
}), [source]);

return <AudioWave {...audioWaveProps} />;
```

### 响应设计

```tsx
<AudioWave
  source={source}
  width="100%"
  height={window.innerWidth < 768 ? 80 : 120}
  style={{ maxWidth: '100%' }}
/>
```

## 类型脚本支持

包含完整类型的全部类型脚本支持 :

```tsx
import type {
  AudioWaveProps,
  AudioWaveController,
  AudioSource,
  UseAudioSourceOptions
} from '@audiowave/react';
```

## 浏览器支持

-   Chrome 66+ (2018年3月) (英语)
-   Firefox 60+ (2018年5月) (英语)
-   Safari 14+ (2020年9月) (英语)
-   79岁以上(2020年1月)

需要Web音频API和MediaStream API支持.

## 许可证

麻省理工学院 [温度](https://github.com/teomyth)

## 常见问题

### @audiowave/react 是什么？

反射音频可视化组件

### 如何安装 @audiowave/react？

在项目目录运行 npm install @audiowave/react，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（\>=16\.8\.0）、react-dom（\>=16\.8\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @audiowave/react 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @audiowave/react 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @audiowave/react 可以商用吗？

@audiowave/react 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @audiowave/react 的下载量有多少？

根据 npm 官方下载统计，@audiowave/react 在 2026/10/07 – 2026/11/05 这 30 天内被下载 784,096 次，日均约 26,137 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @audiowave/react 还在维护吗？

最新版本 0\.6\.2 发布于 2025/10/31（1 年前）；至今共发布 8 个版本，其中过去 12 个月发布了 0 个；首次发布于 2025/07/26。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

