Screenshot Public
HTML
Actualizado Aug 23, 2025
Archivos de Código
Screenshot.html
Código principal
584 líneas
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Akiomae Pro Screen Recorder</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
text-align: center;
max-width: 600px;
width: 100%;
}
h1 {
font-size: 2.5em;
margin-bottom: 30px;
background: linear-gradient(45deg, #fff, #f0f0f0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 15px;
justify-content: center;
margin-bottom: 30px;
}
button {
background: rgba(255, 255, 255, 0.2);
color: #ffffff;
border: 2px solid rgba(255, 255, 255, 0.3);
padding: 12px 24px;
font-size: 1em;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 50px;
font-weight: 600;
min-width: 140px;
}
button:hover:not(:disabled) {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
button.recording {
background: #ff4757;
border-color: #ff4757;
animation: pulse 2s infinite;
}
button.paused {
background: #ffa502;
border-color: #ffa502;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(255, 71, 87, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(255, 71, 87, 0); }
100% { box-shadow: 0 0 0 0 rgba(255, 71, 87, 0); }
}
.status {
margin: 20px 0;
font-size: 1.1em;
font-weight: 500;
}
.timer {
font-size: 1.5em;
font-weight: bold;
color: #ff4757;
margin: 10px 0;
}
video {
margin-top: 20px;
width: 100%;
max-width: 500px;
border-radius: 15px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
}
.floating-preview {
position: fixed;
top: 20px;
right: 20px;
width: 200px;
height: 150px;
background: rgba(0, 0, 0, 0.8);
border-radius: 10px;
overflow: hidden;
display: none;
z-index: 1000;
border: 2px solid #667eea;
}
.floating-preview video {
width: 100%;
height: 100%;
object-fit: cover;
margin: 0;
border-radius: 0;
box-shadow: none;
}
/* Modal de Exportación */
.modal {
display: none;
position: fixed;
z-index: 2000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(5px);
}
.modal-content {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
margin: 5% auto;
padding: 30px;
border-radius: 20px;
width: 90%;
max-width: 500px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
text-align: center;
}
.modal h2 {
margin-bottom: 25px;
font-size: 1.8em;
}
.form-group {
margin-bottom: 20px;
text-align: left;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
}
.form-group input,
.form-group select {
width: 100%;
padding: 12px;
border: none;
border-radius: 10px;
background: rgba(255, 255, 255, 0.2);
color: #fff;
font-size: 1em;
}
.form-group input::placeholder {
color: rgba(255, 255, 255, 0.7);
}
.modal-buttons {
display: flex;
gap: 15px;
justify-content: center;
margin-top: 25px;
}
.btn-primary {
background: #2ed573;
border-color: #2ed573;
}
.btn-secondary {
background: #ff4757;
border-color: #ff4757;
}
.download-info {
margin-top: 15px;
padding: 15px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
font-size: 0.9em;
}
@media (max-width: 768px) {
.container {
padding: 20px;
}
h1 {
font-size: 2em;
}
.controls {
flex-direction: column;
align-items: center;
}
button {
width: 100%;
max-width: 250px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>🎥 Akiomae Pro Recorder</h1>
<div class="status" id="status">Listo para grabar</div>
<div class="timer" id="timer" style="display: none;">00:00:00</div>
<div class="controls">
<button id="startBtn">🔴 Iniciar Grabación</button>
<button id="pauseBtn" disabled>⏸️ Pausar</button>
<button id="stopBtn" disabled>⏹️ Detener</button>
<button id="muteMicBtn" disabled>🎤 Micrófono</button>
<button id="muteSystemBtn" disabled>🔊 Audio Sistema</button>
</div>
<video id="recordedVideo" controls style="display:none;"></video>
</div>
<div class="floating-preview" id="floatingPreview">
<video id="previewVideo" autoplay muted></video>
</div>
<!-- Modal de Exportación -->
<div id="exportModal" class="modal">
<div class="modal-content">
<h2>📁 Exportar Grabación</h2>
<div class="form-group">
<label for="fileName">Nombre del archivo:</label>
<input type="text" id="fileName" placeholder="Mi_Grabacion_2024">
</div>
<div class="form-group">
<label for="fileFormat">Formato de exportación:</label>
<select id="fileFormat">
<option value="webm">WebM (Recomendado)</option>
<option value="mp4">MP4 (Compatible)</option>
<option value="avi">AVI (Alta calidad)</option>
</select>
</div>
<div class="form-group">
<label for="videoQuality">Calidad del video:</label>
<select id="videoQuality">
<option value="high">Alta (Original)</option>
<option value="medium">Media (Comprimido)</option>
<option value="low">Baja (Archivo pequeño)</option>
</select>
</div>
<div class="download-info">
<strong>Información:</strong><br>
Duración: <span id="videoDuration">--</span><br>
Tamaño estimado: <span id="fileSize">--</span>
</div>
<div class="modal-buttons">
<button class="btn-primary" id="downloadBtn">⬇️ Descargar</button>
<button class="btn-secondary" id="cancelBtn">❌ Cancelar</button>
</div>
</div>
</div>
<script>
class ScreenRecorder {
constructor() {
this.mediaRecorder = null;
this.recordedChunks = [];
this.isRecording = false;
this.isPaused = false;
this.startTime = null;
this.pausedTime = 0;
this.timerInterval = null;
this.screenStream = null;
this.audioStream = null;
this.combinedStream = null;
this.recordedBlob = null;
this.initializeElements();
this.bindEvents();
}
initializeElements() {
this.startBtn = document.getElementById('startBtn');
this.pauseBtn = document.getElementById('pauseBtn');
this.stopBtn = document.getElementById('stopBtn');
this.muteMicBtn = document.getElementById('muteMicBtn');
this.muteSystemBtn = document.getElementById('muteSystemBtn');
this.recordedVideo = document.getElementById('recordedVideo');
this.floatingPreview = document.getElementById('floatingPreview');
this.previewVideo = document.getElementById('previewVideo');
this.status = document.getElementById('status');
this.timer = document.getElementById('timer');
this.exportModal = document.getElementById('exportModal');
this.fileName = document.getElementById('fileName');
this.fileFormat = document.getElementById('fileFormat');
this.videoQuality = document.getElementById('videoQuality');
this.downloadBtn = document.getElementById('downloadBtn');
this.cancelBtn = document.getElementById('cancelBtn');
this.videoDuration = document.getElementById('videoDuration');
this.fileSize = document.getElementById('fileSize');
}
bindEvents() {
this.startBtn.addEventListener('click', () => this.startRecording());
this.pauseBtn.addEventListener('click', () => this.togglePause());
this.stopBtn.addEventListener('click', () => this.stopRecording());
this.muteMicBtn.addEventListener('click', () => this.toggleMicrophone());
this.muteSystemBtn.addEventListener('click', () => this.toggleSystemAudio());
this.downloadBtn.addEventListener('click', () => this.downloadVideo());
this.cancelBtn.addEventListener('click', () => this.closeModal());
}
async startRecording() {
try {
// Obtener stream de pantalla
this.screenStream = await navigator.mediaDevices.getDisplayMedia({
video: { mediaSource: 'screen' },
audio: true
});
// Obtener stream de micrófono
try {
this.audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
} catch (e) {
console.log('No se pudo acceder al micrófono:', e);
}
// Combinar streams
const tracks = [...this.screenStream.getTracks()];
if (this.audioStream) {
tracks.push(...this.audioStream.getTracks());
}
this.combinedStream = new MediaStream(tracks);
// Configurar MediaRecorder
this.mediaRecorder = new MediaRecorder(this.combinedStream, {
mimeType: 'video/webm;codecs=vp9'
});
this.mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
this.recordedChunks.push(event.data);
}
};
this.mediaRecorder.onstop = () => {
this.handleRecordingStop();
};
// Manejar cuando el usuario detiene el compartir pantalla
this.screenStream.getVideoTracks()[0].onended = () => {
this.stopRecording();
};
// Iniciar grabación
this.mediaRecorder.start(1000); // Guardar chunks cada segundo
this.isRecording = true;
this.startTime = Date.now();
this.startTimer();
// Mostrar preview flotante
this.previewVideo.srcObject = this.screenStream;
this.floatingPreview.style.display = 'block';
// Actualizar UI
this.updateUI();
this.status.textContent = '🔴 Grabando...';
} catch (error) {
console.error('Error al iniciar grabación:', error);
alert('Error al acceder a la pantalla. Por favor, permite el acceso.');
}
}
togglePause() {
if (!this.mediaRecorder) return;
if (this.isPaused) {
this.mediaRecorder.resume();
this.isPaused = false;
this.pauseBtn.textContent = '⏸️ Pausar';
this.pauseBtn.classList.remove('paused');
this.status.textContent = '🔴 Grabando...';
this.startTimer();
} else {
this.mediaRecorder.pause();
this.isPaused = true;
this.pauseBtn.textContent = '▶️ Reanudar';
this.pauseBtn.classList.add('paused');
this.status.textContent = '⏸️ Pausado';
this.stopTimer();
}
}
stopRecording() {
if (this.mediaRecorder && this.isRecording) {
this.mediaRecorder.stop();
this.isRecording = false;
this.isPaused = false;
// Detener streams
if (this.screenStream) {
this.screenStream.getTracks().forEach(track => track.stop());
}
if (this.audioStream) {
this.audioStream.getTracks().forEach(track => track.stop());
}
this.stopTimer();
this.floatingPreview.style.display = 'none';
this.status.textContent = '⏹️ Procesando grabación...';
}
}
handleRecordingStop() {
// Crear blob del video grabado
this.recordedBlob = new Blob(this.recordedChunks, { type: 'video/webm' });
this.recordedChunks = [];
// Mostrar video grabado
const videoURL = URL.createObjectURL(this.recordedBlob);
this.recordedVideo.src = videoURL;
this.recordedVideo.style.display = 'block';
// Calcular duración y tamaño
this.recordedVideo.onloadedmetadata = () => {
const duration = this.formatTime(this.recordedVideo.duration);
const size = this.formatFileSize(this.recordedBlob.size);
this.videoDuration.textContent = duration;
this.fileSize.textContent = size;
};
// Generar nombre por defecto
const now = new Date();
const defaultName = `Grabacion_${now.getFullYear()}-${(now.getMonth()+1).toString().padStart(2,'0')}-${now.getDate().toString().padStart(2,'0')}_${now.getHours().toString().padStart(2,'0')}-${now.getMinutes().toString().padStart(2,'0')}`;
this.fileName.value = defaultName;
// Mostrar modal de exportación
this.exportModal.style.display = 'block';
// Resetear UI
this.updateUI();
this.status.textContent = '✅ Grabación completada';
}
toggleMicrophone() {
if (this.audioStream) {
const audioTrack = this.audioStream.getAudioTracks()[0];
audioTrack.enabled = !audioTrack.enabled;
this.muteMicBtn.textContent = audioTrack.enabled ? '🎤 Micrófono' : '🎤 Muted';
}
}
toggleSystemAudio() {
if (this.screenStream) {
const audioTracks = this.screenStream.getAudioTracks();
if (audioTracks.length > 0) {
audioTracks[0].enabled = !audioTracks[0].enabled;
this.muteSystemBtn.textContent = audioTracks[0].enabled ? '🔊 Audio Sistema' : '🔊 Muted';
}
}
}
downloadVideo() {
if (!this.recordedBlob) return;
const fileName = this.fileName.value || 'grabacion';
const format = this.fileFormat.value;
// Crear enlace de descarga
const url = URL.createObjectURL(this.recordedBlob);
const a = document.createElement('a');
a.href = url;
a.download = `${fileName}.${format}`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
this.closeModal();
this.status.textContent = '⬇️ Descarga iniciada';
}
closeModal() {
this.exportModal.style.display = 'none';
}
startTimer() {
this.timer.style.display = 'block';
this.timerInterval = setInterval(() => {
const elapsed = Date.now() - this.startTime - this.pausedTime;
this.timer.textContent = this.formatTime(elapsed / 1000);
}, 1000);
}
stopTimer() {
if (this.timerInterval) {
clearInterval(this.timerInterval);
this.timerInterval = null;
}
}
formatTime(seconds) {
const hrs = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
return `${hrs.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
updateUI() {
this.startBtn.disabled = this.isRecording;
this.pauseBtn.disabled = !this.isRecording;
this.stopBtn.disabled = !this.isRecording;
this.muteMicBtn.disabled = !this.isRecording;
this.muteSystemBtn.disabled = !this.isRecording;
if (this.isRecording) {
this.startBtn.classList.add('recording');
} else {
this.startBtn.classList.remove('recording');
this.pauseBtn.classList.remove('paused');
this.timer.style.display = 'none';
}
}
}
// Inicializar la aplicación
document.addEventListener('DOMContentLoaded', () => {
new ScreenRecorder();
});
</script>
</body>
</html>
Comentarios (0)
Inicia sesión para comentar
¡Aún no hay comentarios. Sé el primero en comentar!