Introducción
La mayoría de las herramientas de productividad para navegadores fallan en un punto clave: no impiden activamente las distracciones. Los temporizadores Pomodoro clásicos dependen de tu fuerza de voluntad para respetar el tiempo, pero basta un clic en una notificación o un «solo un minuto más» para romper el flujo. Este artículo detalla cómo construir una extensión de Chrome que no solo mide el tiempo, sino que controla el comportamiento del navegador durante las sesiones, con niveles de enfoque configurables y bloqueo reactivo de tabs.
El enfoque es técnico y práctico: usaremos vibe coding con IA para prototipar una extensión funcional en minutos, iterando hasta lograr un MVP estable. Incluiremos manejo de estados, detección de cambios de tabs, y reglas de bloqueo escalables. Al final, tendrás una base lista para personalizar o integrar con otras herramientas de infraestructura.
Qué es y para qué sirve
Esta extensión implementa un Pomodoro inteligente con tres niveles de enfoque:
- Relajado: Permite cambiar de tabs, pero notifica si te excedes del tiempo configurado.
- Moderado: Bloquea la apertura de nuevas tabs y advierte al intentar salir del tab actual.
- Estricto: Fuerza el retorno al tab de trabajo y evita cualquier cambio de contexto.
La arquitectura se basa en:
- Un popup con interfaz minimalista (generada por IA) que muestra el timer y los controles.
- Un servicio en background que gestiona el estado del timer y las reglas de enfoque.
- Escuchadores de eventos para detectar cambios de tabs y activar/desactivar bloqueos.
- Almacenamiento local para persistir configuraciones y estadísticas básicas.
- Evitar el «scroll infinito» en redes sociales durante sesiones de trabajo.
- Bloquear tabs distractoras (ej: YouTube, Reddit) en modo estricto.
- Integrar con herramientas de DevOps para registrar productividad en dashboards.
Prerequisitos
Antes de empezar, asegúrate de tener instalado y configurado:
| Requisito | Versión mínima | Notas |
|---|---|---|
| **Chrome** | 120+ | Usar Chromium (Edge, Brave) también funciona. |
| **Node.js** | 18+ | Para ejecutar el entorno de desarrollo local. |
| **npm** | 9+ | Incluido con Node.js. |
| **Claude Code** | 0.10+ | Opcional, pero recomendado para vibe coding. |
| **Git** | 2.40+ | Para clonar repositorios de ejemplo. |
| **Permisos** | – | Chrome en modo desarrollador ( BLOCK9 > «Modo desarrollador»). |
- Cuenta de Google para instalar extensiones en modo desarrollador.
- Editor de código (VS Code, Neovim, etc.) con soporte para JavaScript/TypeScript.
Guía paso a paso
Paso 1: Crear la estructura base de la extensión
- Generar los archivos mínimos con IA (recomendado) o manualmente:
mkdir chrome-pomodoro-focus && cd chrome-pomodoro-focus
touch manifest.json popup.html popup.js background.js styles.css
- Configurar el
manifest.json(versión 3):
{
"manifest_version": 3,
"name": "Pomodoro Focus Control",
"version": "1.0",
"description": "Pomodoro con niveles de enfoque y bloqueo de tabs",
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"background": {
"service_worker": "background.js"
},
"permissions": ["activeTab", "tabs", "alarms"],
"icons": {
"16": "icon.png",
"48": "icon.png",
"128": "icon.png"
}
}
Nota: Si no tienes un icon.png, usa uno de Flaticon (8×8 px, formato PNG).- Crear el
popup.htmlcon un botón básico:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>Pomodoro Focus</h1>
<button id="startBtn">Iniciar</button>
<div id="timer">00:00</div>
</div>
<script src="popup.js"></script>
</body>
</html>
- Cargar la extensión en Chrome:
chrome://extensions y activa «Modo desarrollador».– Haz clic en «Cargar extensión sin comprimir» y selecciona la carpeta /chrome-pomodoro-focus.
– Verifica que aparezca el icono en la barra de herramientas.
Paso 2: Implementar el timer Pomodoro básico
- Actualizar
popup.jspara manejar el timer:
let timer;
let seconds = 0;
let isRunning = false;
const workDuration = 25 * 60; // 25 minutos en segundos
document.getElementById('startBtn').addEventListener('click', () => {
if (isRunning) {
clearInterval(timer);
isRunning = false;
document.getElementById('startBtn').textContent = 'Iniciar';
} else {
startTimer(workDuration);
document.getElementById('startBtn').textContent = 'Pausar';
}
});
function startTimer(duration) {
seconds = duration;
isRunning = true;
updateTimerDisplay();
timer = setInterval(() => {
seconds--;
updateTimerDisplay();
if (seconds <= 0) {
clearInterval(timer);
isRunning = false;
alert('¡Tiempo terminado!');
}
}, 1000);
}
function updateTimerDisplay() {
const minutes = Math.floor(seconds / 60);
const secs = seconds % 60;
document.getElementById('timer').textContent =
`${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
- Probar el timer:
– Si cierras y reabres el popup, el timer debe reiniciarse (este comportamiento se corregirá en pasos posteriores).
- Error común:
popup.js esté vinculado correctamente en popup.html y que no haya errores en la consola (Ctrl+Shift+J).Paso 3: Agregar niveles de enfoque y gestión de estado
- Modificar
manifest.jsonpara incluir permisos adicionales:
"permissions": ["activeTab", "tabs", "alarms", "storage"]
- Crear
background.jspara manejar el estado global:
let focusLevel = 'moderado'; // 'relajado', 'moderado', 'estricto'
let currentTabId = null;
// Escuchar cambios de tabs
chrome.tabs.onActivated.addListener((activeInfo) => {
currentTabId = activeInfo.tabId;
enforceFocusLevel(focusLevel);
});
// Escuchar clicks en la barra de herramientas
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'setFocusLevel') {
focusLevel = request.level;
enforceFocusLevel(focusLevel);
}
});
function enforceFocusLevel(level) {
if (level === 'estricto') {
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
if (tabs[0].id !== currentTabId) {
chrome.tabs.update(currentTabId, {active: true});
}
});
}
}
- Actualizar
popup.jspara enviar mensajes al background:
// Agregar opciones de enfoque
const focusOptions = document.createElement('div');
focusOptions.innerHTML = `
<select id="focusLevel">
<option value="relajado">Relajado</option>
<option value="moderado">Moderado</option>
<option value="estricto">Estricto</option>
</select>
`;
document.querySelector('.container').appendChild(focusOptions);
document.getElementById('focusLevel').addEventListener('change', (e) => {
chrome.runtime.sendMessage({
action: 'setFocusLevel',
level: e.target.value
});
});
- Verificar el comportamiento:
– Cambia a «Moderado» y verifica que aparezcan advertencias al intentar salir.
Paso 4: Persistir configuraciones y corregir bugs
- Usar
chrome.storageenbackground.jspara guardar el nivel de enfoque:
// Cargar configuración al iniciar
chrome.storage.sync.get(['focusLevel'], (result) => {
if (result.focusLevel) {
focusLevel = result.focusLevel;
document.getElementById('focusLevel').value = focusLevel;
}
});
// Guardar al cambiar
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'setFocusLevel') {
focusLevel = request.level;
chrome.storage.sync.set({ focusLevel });
enforceFocusLevel(focusLevel);
}
});
- Corregir el bug del timer:
popup.js para usar chrome.alarms y evitar reinicios: // Reemplazar startTimer con:
function startTimer(duration) {
chrome.alarms.create('pomodoroTimer', { delayInMinutes: duration / 60 });
seconds = duration;
isRunning = true;
updateTimerDisplay();
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'pomodoroTimer') {
clearInterval(timer);
isRunning = false;
alert('¡Tiempo terminado!');
}
});
}
- Probar la persistencia:
Consideraciones y buenas prácticas
Limitaciones conocidas
- Chrome API: Las reglas de bloqueo en «Estricto» pueden interferir con extensiones como bloqueadores de anuncios. Usa
chrome.tabs.querypara filtrar tabs del sistema. - Rendimiento: Escuchar eventos de tabs en background puede consumir recursos en ventanas con +50 tabs abiertos. Optimiza con
debounceen los escuchadores. - Cross-browser: Firefox requiere ajustes en
manifest.json(usarmanifest_version: 2para compatibilidad con algunas APIs).
Alternativas de implementación
- Para equipos de SRE: Integrar el timer con Prometheus usando la API de Chrome (
chrome.debugger) para registrar métricas de productividad en tiempo real. - Para DevOps: Extender el background con un WebSocket que envíe eventos a un dashboard interno (ej: Grafana).
Errores comunes y soluciones
| Problema | Causa | Solución |
|---|---|---|
| El timer no persiste al cerrar el popup | Falta usar BLOCK31 | Reemplazar BLOCK32 con BLOCK33 . |
| El bloqueo no funciona en «Estricto» | Permisos faltantes en BLOCK34 | Agregar BLOCK35 a BLOCK36 . |
| La interfaz no se actualiza al cambiar el nivel | Mensajes no sincronizados | Usar BLOCK37 con callbacks. |
Construir una extensión de Chrome para controlar distracciones usando Pomodoro y IA es viable en menos de una hora, iterando con herramientas como Claude Code. La clave está en:
- Enfocarse en el MVP: timer básico + niveles de enfoque + bloqueo reactivo.
- Usar las APIs de Chrome correctamente:
chrome.tabs,chrome.storage, ychrome.alarms. - Validar con pruebas locales: Cambiar de tabs y cerrar/reabrir el popup para detectar fallas de estado.
Esta extensión puede escalarse para equipos de DevOps añadiendo:
- Integración con APIs de monitoreo (Prometheus, Datadog).
- Sincronización entre dispositivos con
chrome.storage.sync. - Reglas de bloqueo personalizadas basadas en URLs o dominios.
- Subir el código a GitHub y configurar GitHub Actions para CI/CD.
- Publicar en Chrome Web Store (requiere pago de $5 USD único).
- Añadir pruebas automatizadas con Jest y Puppeteer.
