Cara Membuat Audio Player dengan Claude Code
Pelajari cara membuat audio player menggunakan Claude Code. Dilengkapi contoh kode praktis dan panduan langkah demi langkah.
Membangun Audio Player dengan Claude Code
Ada banyak situasi yang membutuhkan custom audio player seperti layanan streaming musik, podcast, konten edukasi, dan lainnya. Dengan Claude Code, kamu bisa membangun player profesional yang dilengkapi tampilan waveform dan fungsionalitas playlist.
Implementasi Player Dasar
> Buat custom audio player.
> Dukung play/pause, seek bar, volume, dan perubahan kecepatan pemutaran.
> Implementasikan juga fungsionalitas playlist dan tampilan waveform.
// src/components/AudioPlayer.tsx
'use client';
import { useRef, useState, useEffect } from 'react';
interface Track {
id: string;
title: string;
artist: string;
src: string;
duration: number;
coverArt?: string;
}
interface AudioPlayerProps {
tracks: Track[];
initialTrackIndex?: number;
}
export function AudioPlayer({ tracks, initialTrackIndex = 0 }: AudioPlayerProps) {
const audioRef = useRef<HTMLAudioElement>(null);
const [currentTrackIndex, setCurrentTrackIndex] = useState(initialTrackIndex);
const [isPlaying, setIsPlaying] = useState(false);
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
const [volume, setVolume] = useState(0.8);
const currentTrack = tracks[currentTrackIndex];
useEffect(() => {
const audio = audioRef.current;
if (!audio) return;
const onTimeUpdate = () => setCurrentTime(audio.currentTime);
const onLoadedMetadata = () => setDuration(audio.duration);
const onEnded = () => playNext();
audio.addEventListener('timeupdate', onTimeUpdate);
audio.addEventListener('loadedmetadata', onLoadedMetadata);
audio.addEventListener('ended', onEnded);
return () => {
audio.removeEventListener('timeupdate', onTimeUpdate);
audio.removeEventListener('loadedmetadata', onLoadedMetadata);
audio.removeEventListener('ended', onEnded);
};
}, [currentTrackIndex]);
const togglePlay = () => {
const audio = audioRef.current;
if (!audio) return;
if (audio.paused) {
audio.play();
setIsPlaying(true);
} else {
audio.pause();
setIsPlaying(false);
}
};
const playNext = () => {
const nextIndex = (currentTrackIndex + 1) % tracks.length;
setCurrentTrackIndex(nextIndex);
setTimeout(() => {
audioRef.current?.play();
setIsPlaying(true);
}, 100);
};
const playPrevious = () => {
if (currentTime > 3) {
// Jika lebih dari 3 detik, kembali ke awal
audioRef.current!.currentTime = 0;
} else {
const prevIndex = (currentTrackIndex - 1 + tracks.length) % tracks.length;
setCurrentTrackIndex(prevIndex);
setTimeout(() => {
audioRef.current?.play();
setIsPlaying(true);
}, 100);
}
};
const formatTime = (sec: number) => {
const m = Math.floor(sec / 60);
const s = Math.floor(sec % 60);
return `${m}:${s.toString().padStart(2, '0')}`;
};
return (
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg overflow-hidden max-w-md mx-auto">
<audio ref={audioRef} src={currentTrack.src} preload="metadata" />
{/* Cover Art */}
<div className="aspect-square bg-gray-200 dark:bg-gray-700 relative">
{currentTrack.coverArt ? (
<img src={currentTrack.coverArt} alt={currentTrack.title} className="w-full h-full object-cover" />
) : (
<div className="w-full h-full flex items-center justify-center text-6xl text-gray-400">♪</div>
)}
</div>
{/* Informasi Track */}
<div className="p-6">
<h3 className="text-lg font-bold dark:text-white truncate">{currentTrack.title}</h3>
<p className="text-gray-500 dark:text-gray-400 text-sm">{currentTrack.artist}</p>
{/* Seek Bar */}
<div className="mt-4">
<input
type="range"
min={0}
max={duration || 0}
value={currentTime}
onChange={(e) => {
const time = Number(e.target.value);
audioRef.current!.currentTime = time;
setCurrentTime(time);
}}
className="w-full h-1 accent-blue-600"
/>
<div className="flex justify-between text-xs text-gray-400 mt-1">
<span>{formatTime(currentTime)}</span>
<span>{formatTime(duration)}</span>
</div>
</div>
{/* Kontrol */}
<div className="flex items-center justify-center gap-6 mt-4">
<button onClick={playPrevious} className="text-2xl dark:text-white hover:text-blue-600">⏮</button>
<button
onClick={togglePlay}
className="w-14 h-14 rounded-full bg-blue-600 text-white text-2xl flex items-center justify-center hover:bg-blue-700"
>
{isPlaying ? '⏸' : '▶'}
</button>
<button onClick={playNext} className="text-2xl dark:text-white hover:text-blue-600">⏭</button>
</div>
{/* Volume */}
<div className="flex items-center gap-2 mt-4">
<span className="text-sm dark:text-gray-400">🔊</span>
<input
type="range"
min={0}
max={1}
step={0.05}
value={volume}
onChange={(e) => {
const vol = Number(e.target.value);
audioRef.current!.volume = vol;
setVolume(vol);
}}
className="flex-1 h-1 accent-blue-600"
/>
</div>
</div>
{/* Playlist */}
<div className="border-t dark:border-gray-700 max-h-60 overflow-y-auto">
{tracks.map((track, index) => (
<button
key={track.id}
onClick={() => {
setCurrentTrackIndex(index);
setTimeout(() => { audioRef.current?.play(); setIsPlaying(true); }, 100);
}}
className={`w-full flex items-center gap-3 p-3 text-left hover:bg-gray-50 dark:hover:bg-gray-700 ${
index === currentTrackIndex ? 'bg-blue-50 dark:bg-blue-900/30' : ''
}`}
>
<span className="text-xs text-gray-400 w-6 text-right">
{index === currentTrackIndex && isPlaying ? '♪' : index + 1}
</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium dark:text-white truncate">{track.title}</p>
<p className="text-xs text-gray-500 truncate">{track.artist}</p>
</div>
<span className="text-xs text-gray-400">{formatTime(track.duration)}</span>
</button>
))}
</div>
</div>
);
}
Tampilan Waveform dengan Web Audio API
Sebagai fitur lanjutan, tampilan waveform real-time menggunakan Web Audio API juga bisa diminta ke Claude Code. Dengan menggabungkan AudioContext dan AnalyserNode, waveform audio yang sedang diputar bisa digambar ke Canvas.
Artikel Terkait
Untuk implementasi video player, lihat Panduan Membangun Video Player, dan untuk dukungan responsif, lihat juga Responsive Design.
Untuk detail Web Audio API, lihat MDN (developer.mozilla.org/Web/API/Web_Audio_API).
Upgrade produksi 2026: dari tombol play menjadi audio UI
Audio player bukan sekadar tombol untuk memutar MP3. Ia adalah UI yang membantu pengguna memahami audio apa yang sedang diputar, sudah sampai menit berapa, bagaimana kembali beberapa detik, dan apa langkah berikutnya. Untuk learning content, podcast, produk media, atau halaman jualan, player juga harus menangani progress, error state, accessibility, analytics, dan CTA.
Komponen React/TypeScript di atas adalah dasar yang bisa dijalankan. HTMLAudioElement disimpan dengan useRef, sementara React mengelola track aktif, status play, waktu, dan volume. Saat dipakai di proyek nyata, pastikan tracks tidak kosong, src mengarah ke file audio sungguhan, dan komponen berjalan di client. Setelah itu, waveform, saved progress, preview berbayar, dan consultation CTA bisa ditambahkan tanpa membongkar arsitektur.
HTMLAudioElement vs Web Audio API
HTMLAudioElement adalah object browser di balik elemen audio. Ia menangani loading, decoding, play, pause, seek, volume, duration, metadata, dan event media. Untuk player kursus, podcast, atau product preview, mulai dari API ini. Referensi resmi MDN untuk elemen audio menjelaskan atribut seperti preload, source, dan event.
Web Audio API adalah layer yang lebih rendah. Dengan AudioContext, MediaElementAudioSourceNode, AnalyserNode, dan GainNode, kamu bisa membuat waveform, spectrum, equalizer, fade, dan UI yang bereaksi terhadap suara. Ini bukan pengganti tombol play; ini lapisan tambahan untuk analisis dan efek. Baca dokumentasi Web Audio API dan referensi React useRef agar DOM audio tidak tercampur dengan state biasa.
| Layer | Tanggung jawab | Catatan produksi |
|---|---|---|
| Data | Judul, kreator, URL, durasi, cover, transkrip | Jangan render playlist kosong |
| Playback | HTMLAudioElement untuk play, pause, seek, volume | Tangani loadedmetadata, timeupdate, ended, dan error |
| Visualisasi | Web Audio API untuk waveform atau spectrum | Butuh CORS benar dan AudioContext.resume() setelah aksi user |
| UI | Tombol, slider, playlist, teks waktu | Tambahkan aria-label, fokus keyboard, dan teks screen reader |
| Produk | Analytics, progress, paywall, CTA | Ukur start, 50%, complete, replay, dan click |
Use case nyata untuk konten audio
Use case pertama adalah kursus dan language learning. Peserta butuh speed control, rewind 10 detik, chapter, transcript sync, dan lanjut dari posisi terakhir. Player yang baik membuat proses review terasa ringan.
Use case kedua adalah podcast dan situs media. Player bisa menampilkan cover, chapter, episode terkait, newsletter signup, dan membership CTA. Setelah audio gratis selesai, pengguna sebaiknya diarahkan ke episode lain, subscription, download, atau halaman training.
Use case ketiga adalah storefront kreator. Musik, voice-over, sound effect, dan sample kursus lebih mudah dijual jika calon pembeli bisa mendengar preview pendek. Waveform sederhana plus link Gumroad atau checkout membuat monetization lebih jelas.
Use case keempat adalah internal training. Sales script, contoh customer support, latihan pronunciation, dan compliance audio butuh progress persistence, laporan admin, dan pesan error yang jelas.
Pitfall dan kegagalan konkret
Pitfall paling umum adalah mengandalkan autoplay. Browser modern bisa menolak audio.play() jika belum ada klik atau tap dari user. Karena play() mengembalikan Promise, production code harus menangkap rejection dan memberi instruksi yang jelas.
Kegagalan kedua adalah membaca duration terlalu cepat. Sebelum loadedmetadata, durasi bisa NaN atau 0. Slider perlu nilai maksimum yang aman, dan teks waktu harus siap menampilkan loading state.
Kegagalan ketiga terjadi pada waveform dengan audio dari CDN. Web Audio API membutuhkan header CORS yang benar agar AnalyserNode bisa membaca sinyal. Tes selalu di domain final, bukan hanya localhost.
Masalah lain muncul saat React state tidak sinkron dengan media element. setTimeout setelah ganti track cukup untuk demo, tetapi produk sebaiknya menunggu canplay atau loadedmetadata sebelum memanggil play().
Link, dokumen resmi, dan monetization CTA
Untuk desain state React, lanjutkan ke Claude Code React development. Untuk analisis audio dan waveform, baca Claude Code Web Audio API. Untuk tombol, keyboard, dan screen reader, gunakan Claude Code accessibility.
Jika audio player menjadi bagian dari kursus, paid podcast, atau funnel media, tentukan monetization CTA sejak awal. Alur praktisnya: free preview, email signup, produk berbayar, lalu team consultation bagi tim yang ingin implementasi di repository nyata. ClaudeCodeLab dapat membantu menyusun Claude Code rules, CLAUDE.md, review checklist, dan analytics events melalui training / consultation.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.
Artikel terkait
Workflow Obsidian ke CLAUDE.md untuk Claude Code
Ubah catatan kerja Obsidian menjadi operating note CLAUDE.md agar konteks tidak dijelaskan ulang.
Claude Code Revenue CTA Routing: dari artikel ke PDF, Gumroad, dan konsultasi
Workflow Claude Code untuk mengarahkan pembaca ke PDF gratis, Gumroad, atau konsultasi sesuai intent.
Aturan handoff tim Claude Code: bukti review, permission, rollback, dan jalur revenue
Format handoff Claude Code untuk tim: bukti, permission rule, rollback, PDF gratis, Gumroad, dan konsultasi.