top of page
Buscar

Karaoke de poemas de amor en html

<!DOCTYPE html>

<html lang="es">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Karaoke de Poemas de Amor</title>

<style>

* {

margin: 0;

padding: 0;

box-sizing: border-box;

}


body {

font-family: 'Arial', sans-serif;

background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

min-height: 100vh;

color: white;

padding: 20px;

}


.container {

max-width: 1000px;

margin: 0 auto;

text-align: center;

}


h1 {

font-size: 2.5em;

margin-bottom: 30px;

text-shadow: 2px 2px 4px rgba(0,0,0,0.3);

}


.voice-selector {

background: rgba(255,255,255,0.1);

padding: 20px;

border-radius: 15px;

margin-bottom: 30px;

backdrop-filter: blur(10px);

}


.voice-controls {

display: flex;

flex-wrap: wrap;

gap: 15px;

justify-content: center;

align-items: center;

margin-bottom: 20px;

}


select, input[type="range"] {

padding: 10px;

border: none;

border-radius: 8px;

background: rgba(255,255,255,0.9);

color: #333;

font-size: 1em;

}


select {

min-width: 200px;

}


.range-container {

display: flex;

align-items: center;

gap: 10px;

}


.range-label {

font-size: 0.9em;

min-width: 80px;

}


.karaoke-display {

background: rgba(255,255,255,0.95);

color: #333;

padding: 40px;

border-radius: 20px;

margin: 30px 0;

box-shadow: 0 10px 30px rgba(0,0,0,0.2);

min-height: 300px;

display: flex;

flex-direction: column;

justify-content: center;

}


.poem-title {

font-size: 1.8em;

color: #667eea;

margin-bottom: 30px;

font-weight: bold;

}


.poem-text {

font-size: 1.4em;

line-height: 2;

white-space: pre-line;

}


.current-line {

background: linear-gradient(45deg, #ff6b6b, #ffd93d);

-webkit-background-clip: text;

-webkit-text-fill-color: transparent;

background-clip: text;

font-weight: bold;

transform: scale(1.1);

text-shadow: 2px 2px 4px rgba(0,0,0,0.1);

}


.sung-line {

color: #888;

opacity: 0.7;

}


.upcoming-line {

color: #333;

opacity: 0.5;

}


.controls {

display: flex;

gap: 20px;

justify-content: center;

flex-wrap: wrap;

margin: 20px 0;

}


.btn {

padding: 15px 30px;

border: none;

border-radius: 50px;

font-size: 1.1em;

cursor: pointer;

transition: all 0.3s ease;

box-shadow: 0 5px 15px rgba(0,0,0,0.2);

color: white;

font-weight: bold;

}


.btn-play {

background: linear-gradient(45deg, #4CAF50, #45a049);

}


.btn-pause {

background: linear-gradient(45deg, #ff9800, #e68900);

}


.btn-stop {

background: linear-gradient(45deg, #f44336, #d32f2f);

}


.btn-restart {

background: linear-gradient(45deg, #2196F3, #1976D2);

}


.btn:hover {

transform: translateY(-2px);

box-shadow: 0 8px 25px rgba(0,0,0,0.3);

}


.btn:disabled {

opacity: 0.6;

cursor: not-allowed;

transform: none;

}


.poem-selector {

margin: 20px 0;

}


.poem-selector select {

font-size: 1.1em;

padding: 15px;

min-width: 300px;

}


.status {

background: rgba(255,255,255,0.1);

padding: 10px 20px;

border-radius: 25px;

margin: 10px 0;

font-size: 1.1em;

}


.progress-bar {

width: 100%;

height: 8px;

background: rgba(255,255,255,0.3);

border-radius: 4px;

overflow: hidden;

margin: 20px 0;

}


.progress-fill {

height: 100%;

background: linear-gradient(90deg, #ff6b6b, #4ecdc4);

width: 0%;

transition: width 0.5s ease;

}


@media (max-width: 768px) {

.voice-controls {

flex-direction: column;

gap: 10px;

}

.controls {

flex-direction: column;

align-items: center;

}

.btn {

width: 200px;

}

h1 {

font-size: 2em;

}

.karaoke-display {

padding: 20px;

}

}

</style>

</head>

<body>

<div class="container">

<h1>🎤 Karaoke de Poemas de Amor 🎤</h1>

<div class="voice-selector">

<h3>Configuración de Voz</h3>

<div class="voice-controls">

<select id="voiceSelect">

<option value="">Cargando voces...</option>

</select>

<div class="range-container">

<span class="range-label">Velocidad:</span>

<input type="range" id="rateSlider" min="0.5" max="2" step="0.1" value="1">

<span id="rateValue">1.0</span>

</div>

<div class="range-container">

<span class="range-label">Tono:</span>

<input type="range" id="pitchSlider" min="0.5" max="2" step="0.1" value="1">

<span id="pitchValue">1.0</span>

</div>

<div class="range-container">

<span class="range-label">Volumen:</span>

<input type="range" id="volumeSlider" min="0" max="1" step="0.1" value="1">

<span id="volumeValue">1.0</span>

</div>

</div>

</div>


<div class="poem-selector">

<select id="poemSelect">

<option value="0">Te Amo Más Que...</option>

<option value="1">Eres Más Hermosa Que...</option>

<option value="2">Carta de Amor Eterna</option>

<option value="3">Mi Corazón Te Habla</option>

</select>

</div>


<div class="karaoke-display" id="karaokeDisplay">

<div class="poem-title" id="poemTitle">Selecciona un poema para comenzar</div>

<div class="poem-text" id="poemText">Presiona PLAY para iniciar el karaoke</div>

</div>


<div class="progress-bar">

<div class="progress-fill" id="progressFill"></div>

</div>


<div class="status" id="status">Listo para comenzar</div>


<div class="controls">

<button class="btn btn-play" id="playBtn" onclick="startKaraoke()">▶️ PLAY</button>

<button class="btn btn-pause" id="pauseBtn" onclick="pauseKaraoke()" disabled>⏸️ PAUSA</button>

<button class="btn btn-stop" id="stopBtn" onclick="stopKaraoke()" disabled>⏹️ STOP</button>

<button class="btn btn-restart" id="restartBtn" onclick="restartKaraoke()">🔄 REINICIAR</button>

</div>

</div>


<script>

// Banco de poemas

const poems = [

{

title: "Te Amo Más Que...",

lines: [

"Te amo más que las estrellas aman la noche",

"Más que el océano ama la luna llena",

"Te amo más que las flores aman la primavera",

"Más que el corazón ama cada pena",

"",

"Eres mi respirar, mi despertar",

"Eres la razón de mi existir",

"Te amo más que la vida misma",

"Más que todo lo que pueda decir",

"",

"En cada latido llevas mi nombre",

"En cada suspiro vives tú",

"Te amo más que el infinito",

"Más que todo lo que fue y será"

]

},

{

title: "Eres Más Hermosa Que...",

lines: [

"Eres más hermosa que el amanecer",

"Que pinta el cielo de colores mil",

"Más bella que la rosa más perfecta",

"Que florece en el jardín de abril",

"",

"Tus ojos brillan más que las estrellas",

"Tu sonrisa ilumina mi camino",

"Eres más hermosa que la poesía",

"Más pura que el amor más cristalino",

"",

"En tu belleza encuentro mi refugio",

"En tu mirada veo mi hogar",

"Eres más hermosa que mis sueños",

"Más perfecta que todo lo que hay"

]

},

{

title: "Carta de Amor Eterna",

lines: [

"Si pudiera escribir en las nubes",

"Todas las palabras que guardé",

"El cielo se llenaría de te amo",

"De todo lo que nunca expresé",

"",

"Eres la carta que siempre quise escribir",

"Eres el verso que quiero recitar",

"En cada palabra encuentro tu esencia",

"En cada línea, tu forma de amar",

"",

"Esta carta no tiene final",

"Como mi amor que es eternal",

"Eres mi poema favorito",

"Mi historia más especial"

]

},

{

title: "Mi Corazón Te Habla",

lines: [

"Escucha lo que mi corazón te dice",

"Sin palabras pero con emoción",

"Cada latido lleva tu nombre",

"Cada suspiro, mi devoción",

"",

"Mi alma te busca en cada despertar",

"Mis sueños te dibujan cada noche",

"Eres la melodía que me calma",

"El abrazo que siempre me arrope",

"",

"Que mi corazón sea tu refugio",

"Que mis brazos sean tu hogar",

"Porque amarte es mi propósito",

"Mi razón para despertar"

]

}

];


// Variables globales

let currentPoem = 0;

let currentLine = 0;

let isPlaying = false;

let isPaused = false;

let speechSynthesis = window.speechSynthesis;

let voices = [];

let utterance = null;

let karaokeInterval = null;

let lineTimeout = null;


// Elementos del DOM

const voiceSelect = document.getElementById('voiceSelect');

const rateSlider = document.getElementById('rateSlider');

const pitchSlider = document.getElementById('pitchSlider');

const volumeSlider = document.getElementById('volumeSlider');

const rateValue = document.getElementById('rateValue');

const pitchValue = document.getElementById('pitchValue');

const volumeValue = document.getElementById('volumeValue');

const poemSelect = document.getElementById('poemSelect');

const karaokeDisplay = document.getElementById('karaokeDisplay');

const poemTitle = document.getElementById('poemTitle');

const poemText = document.getElementById('poemText');

const status = document.getElementById('status');

const progressFill = document.getElementById('progressFill');

const playBtn = document.getElementById('playBtn');

const pauseBtn = document.getElementById('pauseBtn');

const stopBtn = document.getElementById('stopBtn');


// Cargar voces disponibles

function loadVoices() {

voices = speechSynthesis.getVoices();

voiceSelect.innerHTML = '';

if (voices.length === 0) {

voiceSelect.innerHTML = '<option value="">No hay voces disponibles</option>';

return;

}


// Filtrar voces en español

const spanishVoices = voices.filter(voice =>

voice.lang.includes('es') || voice.lang.includes('ES')

);


if (spanishVoices.length > 0) {

spanishVoices.forEach((voice, index) => {

const option = document.createElement('option');

option.value = voice.name;

option.textContent = `${voice.name} (${voice.lang})`;

voiceSelect.appendChild(option);

});

} else {

// Si no hay voces en español, mostrar todas

voices.forEach((voice, index) => {

const option = document.createElement('option');

option.value = voice.name;

option.textContent = `${voice.name} (${voice.lang})`;

voiceSelect.appendChild(option);

});

}

}


// Event listeners para los sliders

rateSlider.addEventListener('input', (e) => {

rateValue.textContent = e.target.value;

});


pitchSlider.addEventListener('input', (e) => {

pitchValue.textContent = e.target.value;

});


volumeSlider.addEventListener('input', (e) => {

volumeValue.textContent = e.target.value;

});


// Cambiar poema

poemSelect.addEventListener('change', (e) => {

currentPoem = parseInt(e.target.value);

displayPoem();

stopKaraoke();

});


// Mostrar poema

function displayPoem() {

const poem = poems[currentPoem];

poemTitle.textContent = poem.title;

let poemHTML = '';

poem.lines.forEach((line, index) => {

const className = index < currentLine ? 'sung-line' :

index === currentLine ? 'current-line' : 'upcoming-line';

poemHTML += `<div class="${className}">${line || '&nbsp;'}</div>`;

});

poemText.innerHTML = poemHTML;

// Actualizar barra de progreso

const progress = (currentLine / poem.lines.length) * 100;

progressFill.style.width = `${progress}%`;

}


// Iniciar karaoke

function startKaraoke() {

if (isPaused) {

// Reanudar desde donde se pausó

isPaused = false;

continueKaraoke();

} else {

// Iniciar desde el principio

currentLine = 0;

isPlaying = true;

displayPoem();

speakCurrentLine();

}

updateButtons();

status.textContent = 'Reproduciendo...';

}


// Pausar karaoke

function pauseKaraoke() {

isPaused = true;

isPlaying = false;

speechSynthesis.pause();

clearTimeout(lineTimeout);

updateButtons();

status.textContent = 'Pausado';

}


// Continuar karaoke

function continueKaraoke() {

isPlaying = true;

speechSynthesis.resume();

updateButtons();

status.textContent = 'Reproduciendo...';

}


// Detener karaoke

function stopKaraoke() {

isPlaying = false;

isPaused = false;

speechSynthesis.cancel();

clearTimeout(lineTimeout);

currentLine = 0;

displayPoem();

updateButtons();

status.textContent = 'Detenido';

}


// Reiniciar karaoke

function restartKaraoke() {

stopKaraoke();

currentLine = 0;

displayPoem();

startKaraoke();

}


// Hablar línea actual

function speakCurrentLine() {

const poem = poems[currentPoem];

if (currentLine >= poem.lines.length) {

// Fin del poema

isPlaying = false;

isPaused = false;

updateButtons();

status.textContent = 'Poema completado';

return;

}


const line = poem.lines[currentLine];

if (line.trim() === '') {

// Línea vacía, pasar a la siguiente

currentLine++;

displayPoem();

lineTimeout = setTimeout(() => {

if (isPlaying && !isPaused) {

speakCurrentLine();

}

}, 1000);

return;

}


// Crear nueva instancia de SpeechSynthesisUtterance

utterance = new SpeechSynthesisUtterance(line);

// Configurar voz

const selectedVoice = voices.find(voice => voice.name === voiceSelect.value);

if (selectedVoice) {

utterance.voice = selectedVoice;

}

utterance.rate = parseFloat(rateSlider.value);

utterance.pitch = parseFloat(pitchSlider.value);

utterance.volume = parseFloat(volumeSlider.value);


utterance.onend = () => {

if (isPlaying && !isPaused) {

currentLine++;

displayPoem();

lineTimeout = setTimeout(() => {

if (isPlaying && !isPaused) {

speakCurrentLine();

}

}, 500);

}

};


utterance.onerror = (event) => {

console.error('Error en síntesis de voz:', event);

status.textContent = 'Error en la reproducción';

};


speechSynthesis.speak(utterance);

}


// Actualizar botones

function updateButtons() {

playBtn.disabled = isPlaying && !isPaused;

pauseBtn.disabled = !isPlaying || isPaused;

stopBtn.disabled = !isPlaying && !isPaused;

}


// Inicialización

function init() {

loadVoices();

displayPoem();

updateButtons();

// Recargar voces cuando estén disponibles

if (speechSynthesis.onvoiceschanged !== undefined) {

speechSynthesis.onvoiceschanged = loadVoices;

}

}


// Inicializar cuando la página esté cargada

window.addEventListener('load', init);


// Limpiar al cerrar la página

window.addEventListener('beforeunload', () => {

speechSynthesis.cancel();

});

</script>

</body>

</html>

ree

 
 
 

Comentarios


bottom of page