
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@notross/react-waveform
Advanced tools
A React component for rendering audio waveforms, with support for multiple audio sources and custom styling.
# NPM
npm install @notross/react-waveform
# Yarn
yarn add @notross/react-waveform
The demo project has two components: UI and server:
@notross/react-waveform components and hooksTo run the demo, use the demo script to start both the UI and the server:
# NPM
npm run demo
Your demo will be locally accessible at http://localhost:3030.
interface AudioTrack {
id: number | string
src: string
}
type ConfigColors = {
default: string
active: string
past: string
}
interface ConfigOptions {
colors: ConfigColors
radius: string
activeHeight: string
gap: string
}
import React from 'react'
import { WaveformProvider } from '@notross/react-waveform'
export default function App({ children }: {
children: React.ReactNode,
}) {
return (
<WaveformProvider>
{children}
</WaveformProvider>
)
}
WaveformProvider takes an optional argument of options: ConfigOptions. These options will apply to every <Waveform /> component that does not have its own ConfigOptions set.
import React from 'react'
import { WaveformProvider, ConfigOptions } from '@notross/react-waveform'
const options: ConfigOptions = {
colors: {
active: 'rgba(255, 0, 0, 1)',
default: 'rgba(255, 0, 0, 0.75)',
past: 'rgba(255, 0, 0, 0.5)',
},
activeHeight: '0.375rem',
gap: '2px',
radius: '4px',
}
export default function App(props: React.ComponentProps) {
return (
<WaveformProvider options={options}>
{props.children}
</WaveformProvider>
)
}
// audio-player.tsx
import { AudioTrack, Waveform } from '@notross/react-waveform'
export function AudioPlayer({ track }: {
track: AudioTrack
}) {
return (
<Waveform track={track} />
)
}
<Waveform /> can take three arguments:
track: AudioTrackcolumns: number (optional)options: ConfigOptions (optional)| argument | description | type |
|---|---|---|
track | An object containing the id and src of the track | AudioTrack |
columns | Specifies the number of segments in the rendered audio wave. Default value is 60 | number |
options | Optional styling specifications. These options will override any default options or options set in the WaveformProvider | ConfigOptions |
// custom-audio-player.tsx
import { AudioTrack, ConfigOptions, Waveform } from '@notross/react-waveform'
export function AudioPlayer({ track, activeColor, gap }: {
activeColor: string,
gap: string,
track: AudioTrack
}) {
const options: Partial<ConfigOptions> = {
colors: {
active: activeColor,
},
gap: gap,
}
return (
<Waveform track={track} options={options} />
)
}
The useWaveform hook exposes the following variables and functions:
| name | description | type | arguments |
|---|---|---|---|
armTrack | Plays an audio track from the tracks array | Function | id: number | string |
current | The currently armed track | Object: AudioTrack | |
loading | Status of track array population | boolean | |
loadTracks | Populates the tracks array with a list of audio sources, either replacing the array's contents or appending the passed items to the current array | Function | tracks: AudioTrack[], reset: boolean |
metadata | Data about the currently armed track, such as track duration, time elapsed (while playing) | Object: Metadata | |
tracks | Array of tracks that have been loaded | Object: AudioTrack[] |
The loadTracks function takes the following arguments:
tracks: AudioTrack[]reset: boolean| argument | description | type |
|---|---|---|
tracks | Takes an array of objects specifying the audio tracks to be loaded and rendered as waveforms | AudioTrack[] |
reset | Indicates whether the passed tracks will replace or be appended to the existing array. Default value is false | boolean |
Each track in the tracks array is of type AudioTrack, which includes two properties:
id: string | numbersrc: string| key | description | type |
|---|---|---|
id | The id must be unique, as it is used to synchronize waveforms throughout the application (e.g. if a track's waveform is playing in a list of tracks and is being displayed simultaneously in a separate component) | string or number |
src | The src specifies the location of the audio file. | string |
import { useEffect } from 'react'
import { useWaveform, AudioTrack, Waveform } from '@notross/react-waveform'
// Audio track URLs
const TRACK_LIST = [
'https://demo3.bigfishaudio.net/demo/free11_1.mp3',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/254249/break.ogg',
'https://free-loops.com/data/mp3/d0/b8/bc44c037a3dfdb90838c13513e58.mp3',
'https://free-loops.com/data/mp3/68/c0/af53529e97d928a43d8dd7272ae3.mp3',
]
// URLs mapped to an AudioTrack array
const TRACKS = TRACK_LIST.map((url, index: number) => ({
id: index,
src: url,
}))
export function Tracks() {
const { loadTracks } = useWaveform()
useEffect(() => {
loadTracks(TRACKS) // Load the tracks into the Waveform state
}, [loadTracks])
}
armTrack plays the specified track through an <audio> element in <WaveformProvider>. Once a track is armed, any <Waveform /> whose track id matches the armTrack id will render the audio waveform.
The armTrack function takes only one argument:
id: string | number| argument | description | type |
|---|---|---|
id | The id comes from the tracks array, specifying a loaded track for playback and visualization | string or number |
// play-button.tsx
import { useWaveform } from '@notross/react-waveform'
export function PlayButton({ id }: { id: string }) {
const { armTrack } = useWaveform()
return (
<button onClick={() => armTrack(id)}>{'▶️'}</button>
)
}
current is the currently armed/playing track. If no track is armed, current will evaluate to null.
import { useWaveform } from '@notross/react-waveform'
import { AudioPlayer } from './audio-player.tsx'
export function AudioPlayer() {
const { current } useWaveform()
return (
<>
{/* current is not null */}
{current && (
<div>
<AudioPlayer track={current} />
<p>{`Currently playing track #${current.id}`}</p>
</div>
)}
{/* current is null */}
{!current && <p>No tracks are playing at this time.</p>}
</>
)
}
tracks is an array of all loaded tracks. tracks are of type AudioTrack.
import { useWaveform } from '@notross/react-waveform'
import { AudioPlayer } from './audio-player'
import { PlayButton } from './play-button'
export function TrackList() {
const { tracks } useWaveform()
return (
<ul>
{tracks.map((track) => (
<li key={track.id}>
<PlayButton id={track.id} />
<span>{`Track ID #${track.id}`}</span>
<AudioPlayer track={track} />
</li>
))}
</li>
)
}
metadata returns an object (type Metadata) containing information about the currently armed track, including track duration and playthrough progress (milliseconds/seconds/minutes). metadata includes four properties:
| key | description | type |
|---|---|---|
duration | The length of the track in seconds (decimal) | number |
minutes | The number of minutes elapsed since playback started | number |
seconds | The number of seconds elapsed since playback started | number |
ms | The number of milliseconds elapsed since playback started | number |
WaveformProvider (React Context API )The WaveformProvider maintains the state for all loaded audio tracks, as well as play state.
First, import the WaveformProvider to the root of your application:
import { WaveformProvider } from '@notross/react-waveform';
Next, wrap the provider around the your root component, so that all child components will have access to the WaveformProvider state:
root.render(
<WaveformProvider>
<App />
</WaveformProvider>
);
Any child component of WaveformProvider can utilize the useWaveform hook and the <Waveform /> component.
Finally, load tracks, arm tracks, and render waveforms using the useWaveform hook and the <Waveform /> component:
// audio-tracks.json
[
{
"id": "1",
"src": "https://demo3.bigfishaudio.net/demo/free11_1.mp3"
},
{
"id": "1",
"src": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/254249/break.ogg"
},
{
"id": "1",
"src": "https://free-loops.com/data/mp3/d0/b8/bc44c037a3dfdb90838c13513e58.mp3"
},
{
"id": "1",
"src": "https://free-loops.com/data/mp3/68/c0/af53529e97d928a43d8dd7272ae3.mp3"
}
]
import { useEffect } from 'react';
import { useWaveform, AudioTrack, Waveform } from '@notross/react-waveform';
// import audio tracks
import audioTracks from './audio-tracks.json'
function TrackLibrary() {
const { armTrack, current, loadTracks, tracks } = useWaveform();
// load the tracks into the WaveformProvider context
useEffect(() => {
loadTracks(audioTracks as AudioTrack[])
}, [loadTracks])
return (
<>
<main>
<ul>
{/* List each track with a "play" button and its respective Waveform */}
{tracks.map((track) => (
<li key={track.id}>
<button onClick={() => armTrack(track.id)}>{'▶️'}</button>
<Waveform track={track} />
</li>
))}
</ul>
</main>
<footer>
{/* Render the footer Waveform if a track is currently armed */}
{current && (
<Waveform
track={current}
columns={120}
options={{
colors: {
default: '#ffffff',
},
gap: '1px',
radius: '8px',
}}
/>
)}
</footer>
</>
);
}
localhost media server# File structure
.
├── index.ts # The application
├── media # My local audio files
│ ├── Aubit - Awake Dry Gtr Loop 12 (135bpm) G#maj.wav
│ ├── Aubit - Awake Dry Gtr Loop 47 (75bpm) Dmaj.wav
│ ├── Aubit - Awake Dry Gtr Loop 50 (75bpm) Bmaj.wav
│ ├── Aubit - Awake Dry Gtr Loop 8 (135bpm) C#maj.wav
│ ├── Aubit - Ultrallenium Guitars V2 Loop 10 (148bpm) A#maj Dry.wav
│ └── Aubit - Ultrallenium Guitars V2 Loop 13 (160bpm) Emaj Dry.wav
├── package.json
└── tsconfig.json
Dependencies:
# dependencies
yarn add cors express
yarn add -D @types/cors @types/express
// index.ts
import express, { Request, Response } from 'express';
import { dirname, join } from 'path';
import cors from 'cors';
const app = express();
const port = 8000;
app.use(express.urlencoded({ extended: true }));
app.use(express.static('media'));
app.use(express.json());
app.use(cors())
app.get('/media/:filename', (req: Request, res: Response) => {
return res.sendFile(join(__dirname, 'media', req.params.filename));
});
app.listen(port, () => {
console.log(`⚡️ Server is running on port ${port}`);
});
FAQs
A React component for rendering audio waveforms, with support for multiple audio sources and custom styling.
We found that @notross/react-waveform demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.