Small local app for turning a YouTube URL into an exportable audio slice.
Sample Maker is meant to be a fast local bridge between YouTube references and a DAW/sampler workflow: paste a URL, inspect the waveform, create one or more chops, then export clean audio slices.
- Node.js + Yarn
yt-dlpavailable in your shellffmpegandffprobeavailable in your shell
yarn dev
yarn buildThe dev app runs at http://localhost:5173.
The local API runs at http://localhost:4174 and is proxied by Vite under /api.
Downloaded sources and exported samples are stored under data/jobs, which is ignored by Git.
- Paste a YouTube URL.
- Wait for the local
yt-dlpdownload and WAV conversion. - Drag directly on the waveform to create a chop.
- Adjust the chop visually or with the start/end fields.
- Use space to play/pause the current chop.
- Zoom horizontally when you need finer placement.
- Choose WAV, MP3, or AIFF.
- Export the active chop, or export all chops.
- Local async download jobs with progress from
yt-dlp. - WAV source extraction for waveform display.
- Waveform rendering with
wavesurfer.js. - Multiple draggable/resizable chops.
- Horizontal zoom control.
- Timeline ruler synchronized to waveform scroll.
- Loop playback for the active chop.
- Keyboard shortcuts:
Space: play/pause active chopCmd/Ctrl + Z: undo the last chop edit
- Export to WAV, MP3, or AIFF through
ffmpeg. - Reveal exported files in Finder through the local API.
server/index.js Local Express API around yt-dlp, ffmpeg, ffprobe, and Finder reveal.
src/App.tsx Main React app, WaveSurfer setup, chop state, shortcuts, zoom, export flow.
src/styles.css App layout and visual system.
data/jobs Runtime audio workspace, ignored by Git.
docs/context.md Handoff notes for future development sessions.
AGENTS.md Quick instructions for future coding agents.
This is a local-first tool. It deliberately shells out to globally installed CLIs instead of moving audio work into the browser. Keep generated audio out of Git; data/ is ignored.
If the waveform layout changes, be careful with resize logic. The waveform container has a stable CSS height, and WaveSurfer is resized from that height without observing the WaveSurfer output itself, to avoid resize feedback loops.