Lector dual: el PDF de un libro y su audiolibro, en la misma pantalla y sincronizados. Pensado para leer Mistborn: El Imperio Final mientras suena la narración, con estética de Scadrial — ceniza y bronce.
Un PDF y un MP3 no vienen sincronizados de fábrica, así que Lumina Reader resuelve esa parte con anclajes manuales: le dices en qué página empieza cada capítulo y a partir de ahí puede llevar la página al punto del audio, el audio al punto de la página, o hacer que la página avance sola mientras escuchas.
- Node 22+ (probado con 22.15.1)
- ffmpeg/ffprobe en el PATH, sólo para generar el manifest
winget install Gyan.FFmpeg
npm installColoca los archivos del libro con esta estructura:
public/books/mistborn-1/
├── mistborn_el_imperio_final.pdf
└── audio/
├── ch01.mp3
├── ch02.mp3
└── ...
Un archivo de audio por capítulo. El orden sale del nombre, así que numéralos
con ceros a la izquierda (ch01, no ch1). Si los nombres traen título
—03 - El Superviviente.mp3— se usa como nombre del capítulo.
Genera el manifest y arranca:
npm run manifest
npm run devnpm run manifest recorre los audios con ffprobe y escribe
public/books/mistborn-1/manifest.json con la duración real de cada capítulo.
Se hornean ahí en vez de leerlas en el navegador porque un MP3 VBR sin cabecera
Xing/LAME reporta duración infinita hasta que se escanea entero, y porque así la
lista de capítulos aparece completa en el primer render.
Volver a correrlo conserva los anclajes que ya hubieras hecho.
- Pon el capítulo 1 y busca en el PDF la página donde empieza. Pulsa Anclar.
- Haz lo mismo con algún capítulo más adelante. No hace falta anclarlos todos: los tramos sin anclar se reparten según la duración de sus capítulos.
- Activa Seguir y la página irá avanzando sola con la narración, interpolando entre anclajes. Si pasas página a mano, el seguimiento se apaga solo para no pelearse contigo.
Los dos botones de flecha llevan la página al punto del audio o al revés, una sola vez, sin activar el seguimiento.
| Tecla | Acción |
|---|---|
Espacio |
Reproducir o pausar |
J / L |
Retroceder / adelantar 15 s |
← → |
Página anterior / siguiente |
⇧ + ← → |
Capítulo anterior / siguiente |
+ − |
Acercar / alejar |
0 |
Ajustar al ancho |
A |
Anclar el capítulo en esta página |
G |
Seguimiento automático |
N |
Modo noche del PDF |
C |
Mostrar u ocultar capítulos |
F |
Pantalla completa |
? |
Ayuda |
Todo es local, no hay backend ni cuentas.
Clave de localStorage |
Contenido |
|---|---|
lumina:progress:mistborn-1 |
Capítulo, segundo exacto y página |
lumina:checkpoints:mistborn-1 |
Anclajes capítulo → página |
lumina:prefs |
Velocidad, zoom, seguimiento, modo noche, sidebar |
Los anclajes viven en localStorage y no en el manifest, así que reemplazar los
archivos del libro no borra el mapeo.
El PDF y los MP3 se commitean a public/books/. Con audio partido por capítulos
cada archivo queda muy por debajo del límite de 100 MB de GitHub, pero el
conjunto deja el repo en cientos de MB de forma permanente — git conserva
todo binario en el historial. Conviene que el repositorio sea privado.
Si algún día quieres sacarlos, la app lee todo desde manifest.json con rutas
relativas y nunca importa media desde src/: basta con añadirlos a
.gitignore, sin tocar código.
public/pdfjs/ se genera desde node_modules (scripts/sync-pdfjs-assets.mjs,
que corre solo antes de dev y build) y está en .gitignore. Contiene las
fuentes estándar, los cMaps y el wasm que pdf.js pide por HTTP; sin ellos, los
PDFs que no incrustan sus fuentes se renderizan sin texto.
Vite 8 (Rolldown) · React 19 con React Compiler · Tailwind CSS v4 · react-pdf 10 (pdf.js) · lucide-react · JavaScript
El audio usa el elemento <audio> nativo, sin librería: es lo único que expone
preservesPitch, que es lo que evita que la voz suene aguda al subir la
velocidad.