Skip to content

Music Prompter

What I did

  • Development
  • Deployment

This project comes from a very specific need when singing live: having a song’s lyrics synced to the music, full-screen, without printing them out or memorizing them. Music Prompter is a lyrics teleprompter — you search for a song and its lyrics appear line by line in time with the music, ready to read from the stage.

The app’s “player” is deliberately just a clock: it doesn’t play any real audio, it just advances the active line index using performance.now() and requestAnimationFrame. The reasoning is that whoever’s singing already has their own sound source (a backing track, karaoke, a live band) — what the app needs to provide is a syncable timer, not another audio player. That’s why the live controls include speed and an adjustable offset: they exist to re-align the teleprompter with whatever is actually playing at that moment.

What it offers

  • Streaming-style catalog on the home screen: Apple Music charts (songs and albums) plus instant search.
  • Synced teleprompter: lyrics advance over time with an ambient cover-art background and a full-screen stage mode.
  • Setlists: build song lists for an event and reorder them before going on stage.
  • Playback queue: chain songs together; when one ends, the next starts automatically after a cancelable 10-second countdown.
  • Live controls: speed, sync offset, and font size, all adjustable while singing.

Technical

There’s no UI framework: each Astro component hydrates its own piece of the DOM with an inline module <script>, and all domain logic (playback, lyrics, setlists, queue) lives DOM-free in src/lib. Synced lyrics come from the public lrclib.net API (LRC format, [mm:ss.xx]); when a song only has plain lyrics, they’re spread evenly across the track’s duration as an unsynced fallback. The home charts pull from Apple Music’s RSS feed (with two hosts and formats as fallback) and cover art from the iTunes Search API; if both fail, a fixed list of “stage hits” keeps the catalog from being empty. There’s no backend: setlists persist in localStorage, while the playback queue, meant to last only the current session, lives in sessionStorage. Built solo by Héctor Torres with Astro 7 and Tailwind CSS 4, deployed on Cloudflare Pages.

Este proyecto nace de una necesidad muy concreta al cantar en directo: tener la letra de una canción sincronizada en el tiempo, en pantalla completa, sin depender de imprimirla o de aprendérsela de memoria. Music Prompter es un teleprompter de letras — buscas una canción y su letra va apareciendo línea a línea al ritmo de la música, lista para leerse desde el escenario.

El “player” de la app es deliberadamente solo un reloj: no reproduce ningún audio real, sino que avanza el índice de línea activa con performance.now() y requestAnimationFrame. La razón es que quien canta ya trae su propia fuente de sonido (pista de acompañamiento, karaoke, banda en directo) — lo que necesita la app es un cronómetro sincronizable, no un reproductor más. De ahí que los controles en directo incluyan velocidad y un desfase (offset) ajustable: sirven para recolocar el teleprompter sobre lo que realmente está sonando en cada momento.

Qué ofrece

  • Catálogo tipo streaming en el inicio: charts de Apple Music (canciones y álbumes) más una búsqueda instantánea.
  • Teleprompter sincronizado: la letra avanza en el tiempo con carátula ambiental de fondo y modo escenario a pantalla completa.
  • Setlists: crea listas de canciones para un evento y ordénalas antes de subir al escenario.
  • Cola de reproducción: encadena canciones; al terminar una, la siguiente arranca sola tras una cuenta atrás de 10 segundos, cancelable en cualquier momento.
  • Controles en directo: velocidad, desfase de sincronía y tamaño de letra, todo ajustable mientras se canta.

Técnico

Sin framework de UI: cada componente Astro hidrata su propio trozo de DOM con un <script> de módulo, y toda la lógica de dominio (reproducción, letras, setlists, cola) vive separada del DOM en src/lib. La letra sincronizada viene de la API pública de lrclib.net (formato LRC [mm:ss.xx]); si una canción solo tiene letra plana, se reparte uniformemente a lo largo de la duración como alternativa no sincronizada. Los charts de portada usan el RSS de Apple Music (con dos hosts y formatos como respaldo) y las carátulas la API de búsqueda de iTunes; si todo falla, una lista fija de “hits de escenario” evita que el catálogo quede vacío. No hay backend: los setlists persisten en localStorage y la cola de reproducción, pensada para durar solo la sesión, en sessionStorage. Construido en solitario por Héctor Torres con Astro 7 y Tailwind CSS 4, desplegado en Cloudflare Pages.