GPT Image 2.5 Flare & Sunburst are live on EvoLinkTry GPT Image 2.5
An exploded assembly of precision metal interaction components
Use Cases

How to Turn Requirements into an Interactive Prototype with AI

EvoLink Team
EvoLink Team
Product Team
October 16, 2026
10 min read

A prototype has polished cards and working-looking buttons, but confirming a booking changes nothing. Turning requirements into an interactive prototype means specifying behavior, not just asking for a screen.

Write the states and acceptance cases first, then generate the smallest runnable interface that demonstrates them. A local HTML file is enough to review a flow before building an application backend.

Define the prototype's one decision

Use a fictional two-session booking example. A visitor chooses morning or afternoon; each starts with two available places. Confirmation reserves one place, repeated confirmation must not reserve another, and cancellation restores that place.

The demo uses page memory only. Reloading resets it, and another browser tab does not share its capacity. That is an explicit review boundary, not a hidden production booking system.

StateUser actionExpected result
Nothing selectedAttempt confirmationConfirmation unavailable; capacity stays 2/2
Morning selectedConfirmMorning becomes 1; booking is morning
Already bookedRepeat confirmationNo second decrement
Already bookedCancelMorning returns to 2; booking clears
No bookingCancel againCapacity stays unchanged
Full morning scenarioSelect Morning, then AfternoonMorning stays 0 and cannot be booked; Afternoon can be booked
Switch review scenarioChange the starting availabilityClear booking and selection; restore the selected scenario

This table is more precise than “make the form intuitive.” It gives the model and reviewer a shared definition of success.

Give AI the behavior and implementation scope

Build a single-file HTML prototype for the supplied booking flow.
Use native label/select/button controls and visible status text.
Initial capacity: morning 2, afternoon 2. One booking per page session.
No selection: disable confirmation. Confirm only when selected capacity is positive.
While booked: block repeated confirmation and selection changes.
Cancel: restore exactly one place to the booked slot, then clear the booking.
Repeated cancel is a no-op. Announce updates in a polite live region.
No external libraries, network calls, personal data, payment, or persistence.
Return complete HTML, instructions to open it, and acceptance cases.
Do not claim concurrency or production reservation guarantees.
Use the Agent or API path on the EvoLink Gemini 4 page. Ask for the complete file rather than a screenshot or a list of components. Keep the requirements next to the code so changes can be checked against the same contract.

Send the state table with the prompt and ask for one complete HTML file. Open that file and run the acceptance cases below; a screenshot or a response saying “implemented” is not the review artifact.

  1. Open the EvoLink Gemini 4 page and follow its Agent or API instructions. Supply the state table and prompt together. Add the review scenario below: normal availability is 2/2; the full-morning scenario starts at 0/2 and resets both selection and booking. Ask for a readable layout, remaining places, and explicit confirmation, cancellation, and full-session messages.
  2. Request one complete HTML document, including its styles and script. With an Agent, ask it to save booking.html; with an API client, save the returned HTML text as that file, excluding Markdown fences. Do not save the JSON response envelope as HTML. Check that the file contains no unexpected remote scripts or requests before opening it.
  3. Open booking.html in a browser. In the normal scenario, select Morning and confirm: the remaining count must change from 2 to 1, with a visible booking message. Cancel: the count returns to 2 and selection clears. Repeat cancellation through a test handler: the count must remain 2.
  4. Switch to Morning full and select Morning: show 0 remaining, explain that it is full, and disable confirmation. Choose Afternoon and confirm: its count changes from 2 to 1. Switching back to Normal clears the booking and restores 2/2. Scenario controls set test data; they do not simulate other users or backend concurrency.
  5. If a check fails, send the input state, exact clicks, expected result, actual result, and HTML back through the same integration. Request a targeted fix, then rerun both scenarios. Record accepted output and usage before comparing another model through the gateway; generating a file alone does not establish quality or cost efficiency.

A complete runnable reference prototype

Save this reference as booking.html and open it in a browser:

The reference below is an authored teaching example, not a recorded model response. It keeps the interface in English across all language versions so the executable file stays identical. Its layout and status messages make the flow reviewable; they are not a finished product design.

<!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>
Native button elements provide actual keyboard-operable controls. The status uses an ARIA live region so changes can be announced without moving focus. These choices still need keyboard and assistive-technology review in the target environment.

Test behavior before polishing the layout

Start with no selection and verify confirmation is disabled. Choose morning, confirm, and check that the status says booked. Cancel and verify both capacities return to two. Repeat cancellation through the UI or automated checks and ensure it cannot create a third place.

Then try another slot. Check the booking is cleared before changing the next selection. The handler's checks matter even though the button is disabled: the state transition should remain valid if code invokes the handler again.

The full-session case is now directly testable through Review scenarios. Network errors and pending requests remain outside this local example; define those states before adding a real service.

Find gaps in the requirements, not only bugs in HTML

ObservationQuestion to settle
User wants to switch sessions after bookingIs this cancel-and-rebook or a separate transfer action?
Two people book the final placeWhat server owns capacity and rejects conflicts?
Reload loses the bookingIs persistence in scope for this prototype?
Reviewer cannot use the keyboardAre labels, focus order, and feedback sufficient?

The next implementation phase should put authoritative capacity and reservation logic on a backend with the required conflict handling. Do not treat the local counter as evidence that concurrent booking works.

For a real Next.js application, use the repository's component system and state boundaries instead of pasting a standalone page into production. The HTML file is a review artifact that makes the product decision concrete.

Hand off requirements with the working file

Save the requirement revision, prototype, acceptance table, observed test results, and unresolved product questions. If a reviewer changes the cancellation rule, update both the state table and interface, then rerun the affected cases.

For a learning activity with source-grounded questions and scoring, continue with the article-to-quiz workflow.

FAQ

Does a clickable prototype need a backend?

Not for demonstrating this local flow. Shared reservations and persistent capacity do require an authoritative implementation.

What should I supply besides a design reference?

States, actions, expected results, failure behavior, and scope. A picture alone does not define the transition rules.

Is disabling the button sufficient validation?

Also check the transition handler. UI state should not be the only thing preventing invalid updates.

Why test cancel twice?

It catches logic that restores capacity more than once for one booking.

Can I copy this directly into production?

Adapt it to the application architecture and implement the missing backend, validation, and accessibility requirements before relying on it.

What makes the prototype ready for review?

It opens, the agreed interactions work, limitations are visible in the handoff, and the reviewer can reproduce the acceptance cases.

Sources

Connect AI models through one API

Compare models and current pricing, then follow the API documentation to integrate your chosen model.