
Cómo crear un prototipo interactivo con IA a partir de requisitos
Unas tarjetas pulidas y botones aparentes no bastan si confirmar una reserva no cambia nada. Para convertir requisitos en un prototipo hay que definir el comportamiento.
Definir una decisión que comprobar
En el ejemplo ficticio hay mañana y tarde, con dos plazas iniciales cada una. Confirmar reserva una plaza; repetir no descuenta otra; cancelar devuelve una al turno reservado.
Solo usa memoria de página. Recargar reinicia y otra pestaña no comparte capacidad. Es el límite del ejemplo, no un sistema real de reservas.
| Estado | Acción | Resultado |
|---|---|---|
| Sin selección | Intentar confirmar | Desactivado, plazas 2/2 |
| Mañana seleccionada | Confirmar | Mañana 1, reserva de mañana |
| Reservado | Repetir confirmación | Sin segundo descuento |
| Reservado | Cancelar | Mañana vuelve a 2, reserva borrada |
| Sin reserva | Cancelar otra vez | Capacidad igual |
| Mañana completa | Seleccionar Morning y después Afternoon | La mañana permanece en 0 y no admite reservas; la tarde sí |
| Cambiar de escenario | Modificar la disponibilidad inicial | Borrar reserva y selección; restablecer el escenario elegido |
La tabla da un criterio común, más preciso que pedir una interfaz intuitiva.
Dar a la IA comportamiento y alcance
Construye un prototipo de reserva en un archivo HTML.
Usa controles nativos label/select/button y estado visible.
Capacidad inicial: mañana 2, tarde 2. Una reserva por sesión de página.
Sin selección, desactiva confirmar; exige capacidad positiva.
Con reserva, impide reconfirmación y cambio de selección.
Cancelar devuelve exactamente una plaza al turno reservado y borra la reserva.
Repetir cancelar no hace nada. Anuncia cambios con una región live polite.
Sin bibliotecas, red, datos personales, pagos ni persistencia.
Devuelve HTML completo, apertura y casos de aceptación.
No afirmes garantías de concurrencia o reserva en producción.Envíe la tabla de estados con el prompt y solicite un HTML completo. Ábralo y recorra los casos de aceptación; una captura o la palabra «implementado» no sustituyen al archivo funcional.
De la solicitud a EvoLink al archivo que puedes revisar
- Abre la página de Gemini 4 en EvoLink y sigue las instrucciones de Agent o API. Envía juntos la tabla de estados y el prompt. Añade dos escenarios: disponibilidad normal 2/2 y mañana completa 0/2. Cambiar de escenario borra la selección y la reserva. Pide un diseño legible, plazas restantes y mensajes claros de confirmación, cancelación y aforo completo.
- Solicita un documento HTML completo, con estilos y script. Con un Agent, pide guardarlo como
booking.html; con un cliente API, guarda el texto HTML devuelto sin los delimitadores Markdown. No guardes la envoltura JSON como HTML. Antes de abrirlo, comprueba que no incluya scripts remotos ni peticiones de red inesperadas. - Abre
booking.htmlen el navegador. En el escenario normal, selecciona Morning y confirma: las plazas pasan de 2 a 1 y aparece la confirmación. Cancela: vuelven a 2 y se borra la selección. Invocar otra vez el controlador de cancelación en una prueba debe mantener el contador en 2. - Cambia a Morning full y selecciona Morning: deben aparecer 0 plazas, un aviso de aforo completo y la confirmación desactivada. Afternoon sigue disponible; al confirmar, sus plazas pasan de 2 a 1. Volver a Normal borra la reserva y restablece 2/2. Este control prepara datos de prueba; no simula otros usuarios ni concurrencia en el servidor.
- Si algo falla, devuelve por la misma integración el estado inicial, los clics, el resultado esperado, el resultado real y el HTML. Pide una corrección concreta y repite ambos escenarios. Registra los resultados aceptados y el consumo antes de comparar otro modelo mediante la pasarela; generar un archivo no demuestra por sí solo calidad ni ahorro.
Prototipo de referencia ejecutable
booking.html y ábrelo:La referencia siguiente es un ejemplo didáctico escrito, no una respuesta registrada de un modelo. La interfaz permanece en inglés en todos los idiomas para mantener idéntico el archivo ejecutable. El diseño y los mensajes permiten revisar el flujo, pero no representan el diseño final del producto.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Session booking · Review prototype</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; background: #f4f6f8; color: #172033; font: 16px/1.6 system-ui, sans-serif; }
main { max-width: 640px; margin: 48px auto; padding: 28px; background: white; border: 1px solid #dce2ea; border-radius: 16px; }
h1 { margin: 8px 0; font-size: 30px; line-height: 1.2; }
p { margin: 12px 0; }
.eyebrow { color: #526077; font-size: 13px; text-transform: uppercase; letter-spacing: .08em; }
label { display: block; font-weight: 600; margin: 16px 0 6px; }
select, button { font: inherit; padding: 10px 14px; border: 1px solid #aeb9c8; border-radius: 8px; }
select { width: 100%; background: white; color: #172033; }
.actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
button { cursor: pointer; background: white; color: #172033; }
#confirm { background: #193e87; color: white; border-color: #193e87; }
button:disabled { opacity: .5; cursor: not-allowed; }
:focus-visible { outline: 3px solid #b56b00; outline-offset: 3px; }
#status { background: #edf3fc; padding: 16px; border-radius: 8px; }
small { display: block; color: #526077; }
fieldset { margin: 28px 0 0; padding: 16px; border: 1px dashed #aeb9c8; border-radius: 8px; }
legend { font-weight: 600; }
@media (max-width: 680px) { main { margin: 16px; padding: 20px; } }
</style>
</head>
<body><main>
<p class="eyebrow">Interactive prototype · Local demo</p>
<h1>Book a workshop session</h1>
<p>Choose a session, confirm your place, or cancel to release it.</p>
<p id="capacity"></p>
<label for="slot">Session</label>
<select id="slot"><option value="">Choose a session</option>
<option value="am">Morning</option><option value="pm">Afternoon</option></select>
<div class="actions">
<button id="confirm" type="button" disabled>Confirm booking</button>
<button id="cancel" type="button" disabled>Cancel booking</button>
</div>
<p id="status" role="status" aria-live="polite"></p>
<small>One booking per page. Refresh resets this demo; other tabs do not share availability.</small>
<fieldset><legend>Review scenarios</legend>
<label for="scenario">Starting availability</label>
<select id="scenario"><option value="normal">Normal · 2 morning / 2 afternoon</option>
<option value="full">Morning full · 0 morning / 2 afternoon</option></select>
<p><small>Changing the scenario clears the current booking and selection. This control is for review only.</small></p>
</fieldset>
</main>
<script>
const capacity = { am: 2, pm: 2 };
const names = { am: "Morning", pm: "Afternoon" };
let selected = "";
let booking = null;
const slot = document.getElementById("slot");
const scenario = document.getElementById("scenario");
const confirmButton = document.getElementById("confirm");
const cancelButton = document.getElementById("cancel");
const status = document.getElementById("status");
const availability = document.getElementById("capacity");
function render(message = "") {
const valid = Object.hasOwn(capacity, selected);
confirmButton.disabled = !valid || booking !== null || capacity[selected] <= 0;
cancelButton.disabled = booking === null;
slot.disabled = booking !== null;
availability.textContent = `Available: morning ${capacity.am}, afternoon ${capacity.pm}`;
status.textContent = message || (booking !== null
? `Booked: ${names[booking]}. Your place is reserved in this demo.`
: valid && capacity[selected] === 0
? `${names[selected]} is full. Choose another session.`
: "Choose a session to book your place.");
}
slot.addEventListener("change", () => { selected = slot.value; render(); });
confirmButton.addEventListener("click", () => {
if (!Object.hasOwn(capacity, selected) || booking !== null || capacity[selected] <= 0) return;
capacity[selected] -= 1;
booking = selected;
render();
});
cancelButton.addEventListener("click", () => {
if (booking === null) return;
const cancelled = names[booking];
capacity[booking] += 1;
booking = null;
selected = "";
slot.value = "";
render(`${cancelled} booking cancelled. Your place has been released.`);
});
scenario.addEventListener("change", () => {
capacity.am = scenario.value === "full" ? 0 : 2;
capacity.pm = 2;
booking = null;
selected = "";
slot.value = "";
render("Review scenario reset. Choose a session to test it.");
});
render();
</script>
</body></html>Probar comportamiento antes del diseño
Sin selección, confirmar debe estar desactivado. Elige mañana, confirma y revisa el estado. Cancela y comprueba dos plazas en ambos turnos. Repite cancelar mediante interfaz o pruebas: no puede aparecer una tercera plaza.
Prueba después tarde y verifica que se borra la reserva antes de cambiar. Los controles del manejador también importan: desactivar el botón no basta si otro código lo invoca otra vez.
El aforo completo ya se puede comprobar directamente en Review scenarios. Los errores de red y las solicitudes pendientes quedan fuera de este ejemplo local; define esos estados antes de conectar un servicio real.
Detectar huecos del requisito
| Observación | Pregunta |
|---|---|
| Cambiar de turno después de reservar | ¿Cancelar y reservar o transferencia independiente? |
| Dos personas quieren la última plaza | ¿Qué servidor controla capacidad y conflictos? |
| Recargar pierde la reserva | ¿Incluye persistencia el alcance? |
| No se puede usar con teclado | ¿Bastan etiquetas, orden de foco y avisos? |
La implementación posterior necesita capacidad autoritativa y conflictos en backend. El contador local no prueba concurrencia.
En Next.js reutiliza el sistema de componentes y límites de estado del proyecto, sin pegar esta página directamente en producción. Es un artefacto para hacer concreta una decisión de producto.
Entregar requisitos y archivo juntos
Guarda revisión, prototipo, aceptación, resultados observados y preguntas pendientes. Si cambia cancelación, actualiza tabla e interfaz y repite las pruebas afectadas.
Preguntas frecuentes
¿Necesita backend un prototipo clicable?
No para este flujo local. Reservas compartidas y capacidad persistente sí necesitan una implementación autoritativa.
¿Qué doy además del diseño?
Estados, acciones, resultados, fallos y alcance. Una imagen no define transiciones.
¿Basta con desactivar el botón?
Comprueba también el manejador para impedir actualizaciones inválidas.
¿Por qué cancelar dos veces?
Detecta que se devuelva más de una plaza para una reserva.
¿Puedo copiarlo a producción?
Adáptalo a la arquitectura y completa backend, validación y accesibilidad antes de depender de él.
¿Cuándo está listo para revisión?
Abre, cumple las interacciones acordadas y permite reproducir pruebas con límites conocidos.


