Skip to main content
Version: 0.1.135

UI prototypes

For a feature with a user interface, the design is settled before the code is written. A prototype is that design, made concrete enough to react to.

Why a prototype comes first​

An agent asked to implement a screen has to decide what it looks like. Left to itself it will decide something reasonable and you will disagree with it after the code exists, which is the expensive moment to disagree. A prototype moves that conversation earlier, when changing your mind costs a regeneration instead of a rewrite.

Three kinds​

HTML prototypes are standalone: fast to produce, fast to change, not running on your stack. A design can also come from Figma, where the options are drawn in a Figma file.

Target-stack prototypes are built and run on the project's own stack, so what you are looking at is the real thing. A feature's target-stack prototype is the first work on the feature's own branch: when the feature is implemented, the implementation continues from it on that same branch, replacing its placeholder parts with the real thing rather than starting the screen again.

Both are on the feature's Preview tab: Design for the design options, and Implementation for the feature's branch running on your stack — first its prototype, then its implementation. While the branch holds only the prototype, Rebuild from the design revises it and Remove prototype takes it off the branch, both after asking. Once implementation has started on top of it, those two go away and the implementation's own controls take over, because the prototype is now where the implementation started.

In the features list, a feature whose branch holds only its prototype shows the status Prototype, so you can always tell a prototype from an implementation.

Each reviewer gets their own target-stack preview. What you click, the screen you are on and the account you sign into the prototype with are yours alone, so a colleague reviewing the same feature does not move your screen. You can also keep several features' previews open side by side, each in its own browser tab.

The design source and whether a target-stack preview is built are independent project settings, so you can work from an HTML design and still have it reproduced on your stack.

Storybook prototypes skip the separate design altogether: the prototype is the code. An agent builds the feature's pages as your project's own components, routed into the app as the finished feature will be, with one Storybook story for each To-Be scenario and fake data for every call the pages make to the backend. What you approve is the code that ships, so there are no design options to choose between and nothing to rebuild on your stack afterwards.

  • It is offered for a frontend written in React 18 or later with Vite, Vue 3 with Vite, or Angular 15 to 22, once the project can run in development mode. Choose it under Settings → Integrations → Prototypes → Prototype Mode: Storybook — real components with a story per state. For any other frontend the option is greyed out and says what is missing — needs a React, Vue 3 or Angular 15+ frontend, or needs the project's dev environment first.

  • Choosing it sets Storybook up in your codebase straight away; there is nothing else to click. An agent installs Storybook (or extends the one you already have, keeping your own stories and settings), and Repave checks the result before anything lands: Storybook must start, a story must render inside your app with no request leaving its environment, the rendered elements must carry their source locations, links that would open a new tab must stay in the story, every dependency it added must be pinned to an exact version, and your project's own tests, type check and build must give the results they gave before. If any check fails, nothing is changed and the card says which check, in plain words, with Retry.

  • When the project merges through pull requests, setup arrives as a pull request you review like any other, and prototypes can be generated once it is merged. On a project that combines several repositories, that pull request goes to the repository the frontend lives in.

  • A feature's Preview tab then shows Stories instead of Design. Generate prototype builds it, and stays greyed out, with the reason under it, while setup is still running or has failed, while a new project has no application shell at all yet — no shell stories, no merged shell and no shell designed before switching to Storybook (each feature's stories render inside it; the reason links to where you generate them) — or while the feature has no To-Be scenarios yet. A project with an existing codebase of its own does not wait for the shell. While it builds, the pane counts the stories that render so far; you can leave the page. Every story is rendered before the prototype is kept: a story that does not render, or one that tries to reach an outside address, fails the build and is named, with Try again.

  • Each story is a picture of one state, and holds still: a scenario that moves the user on — signing in and landing on Accounts — is shown as where it ends, the Accounts page signed in, rather than acted out. A story that moves to another page on its own, or whose scripted steps fail, fails the build the same way, naming the story and where it went. Instructions you give for a build are kept when the build is sent back and tried again.

  • A feature whose branch was started before Storybook was set up cannot build one until the branch is brought up to date: the build stops before anything changes and says so. Update feature branches, under Settings → Integrations, brings it up to date; then press Try again.

  • Switching a project that is already under way keeps what you approved. A feature whose HTML or Figma design was chosen before the switch gets a Design view beside Stories: the design itself, as it looked before the switch, read-only, with Open in tab. The Preview tab opens on it while the feature has no stories. From there you have two ways on:

    • Implement (beside the views) builds that design: the UI check compares the result with it, as it did before the switch, and the implementation also writes a story for each of the feature's To-Be scenarios, which are checked like a generated prototype's.
    • Generate stories, on Stories, builds the stories from the To-Be scenarios first, if you would rather review the screens as stories before they are implemented.

    Either way the feature then has stories and is reviewed and adjusted through them; Design stays as a reference for what was approved.

  • The prototype is the first work on the feature's branch, like a target-stack prototype. Calls the backend does not answer yet are marked as placeholders, which the implementation replaces.

  • The application shell is written the same way, before any feature: as your app's own components with a story for each of its states, on the Navigation & Shell page (see Navigation and shell).

Where a prototype runs​

A target-stack prototype runs in the feature's own environment — the same one its implementation runs in later — so features' prototypes never wait for one another and can be built at the same time. Its controls are the Env menu's, described under the implementation below: Restart, Stop, and Add test data… to fill its database.

A Storybook prototype runs in an environment of its own that runs Storybook and nothing else — no database, no backend and no app — because its stories render with fake data. It is ready as soon as Storybook answers, and it starts, stops and goes idle independently of the Implementation view's environment; its Env menu, headed This feature's stories environment, has Restart and Stop. Opening Implementation starts that view's own environment, as it always does, and the story keeps showing. A project whose dev configuration does not say how to start Storybook cannot start its stories, and the view says so.

While a story is showing, a dropdown in the preview's bar, beside Reload, lists one story per To-Be scenario, in the order of the feature's scenarios; choose one to show it. Other stories your codebase has for the feature are not listed, though Repave still checks that they render: a state you want to see that no scenario covers is a missing scenario — ask for it in Adjust, and the agent proposes it. The dropdown shows the chosen story's name (hover it for the whole name). The browser shows the story itself, inside your app's real shell: there is no address bar, and links in the app move from page to page without leaving the story. A stopped prototype says The prototype is not running. with Start, which opens the story you last chose; while it starts it says Starting the prototype…, and if it cannot start it says why, with Try again and its log.

A prototype is built without the application shell when the shell was not yet on the base branch when the prototype was started. Rebuild from the design keeps that starting point, so it does not add the shell: to include it, remove the prototype and build it again once the shell is merged.

Options, and choosing between them​

An HTML or Figma prototype comes as options rather than a single answer. You pick the one to carry forward, and the implementation agent reproduces the option the feature selected — not a fresh interpretation of the scenarios.

Options can be opened in their own browser tab when the embedded preview is too small to judge.

Seeing the implementation​

Once a feature has code to run, the Preview tab's Implementation view shows the real thing: the feature's own branch, running in development mode on the feature's page, with the same dev configuration the target-stack prototype runs from. It does not need a UAT configuration, and you do not need to go to UAT Tools to find it.

  • A feature waiting for your acceptance opens on it, and its implementation starts by itself. Each feature runs in an environment of its own, so starting yours never stops anyone else's. While it starts, the view lists each step and can show the log as it is written.

  • A project that cannot run in development mode yet says why, in the same words as the target-stack preview's setting. When what is missing is the dev configuration, Generate the dev configuration creates it, and the implementation starts by itself once it is ready. The configuration is committed to your integration branch (in pull-request mode, proposed as a pull request), so every feature branch carries it. In Repave IDE, /repave:dev-config writes or repairs the same file from your own session, and you commit it with the feature.

  • The app is shown by a browser that runs beside it on the server, so it opens the app at the address the app itself expects — sign-in redirects and anything else that names its own address work as they do for the people who will use it. You can click, type, scroll and select in it as in any browser, with back, forward, reload and an address bar for the app's own routes. As with the target-stack preview, that browser is yours alone: a colleague looking at the same feature has their own, and does not move your screen or share your sign-in.

  • Controls that a browser normally draws outside the page are drawn by the preview instead, where the app has them:

    • a dropdown opens its list of options over the app; choose one as you would in a browser;
    • a date, time or colour field opens a small box holding the same field in your own browser, with your browser's calendar or colour picker; picking a value applies it and closes the box, and a value you type is finished with Done (Clear empties a field that is not required);
    • a field with suggestions lists the ones that match what you type, under the field. The app sees your choice exactly as it would see one made in its own page.
  • When the app shows an alert, confirmation or prompt, it appears over the preview — headed The app says or The app asks — and waits for your answer; the rest of the feature page stays usable. Leaving a page with unsaved changes asks Leave this page? with Stay and Leave. A question still waiting is asked again if you reload the feature page.

  • A link or button that opens a new tab opens it in the preview: a strip of tabs appears above the address bar with the new tab chosen, and back, forward, reload and the address follow the tab you choose. The first tab is the preview itself and stays; close any other with its ×, which returns you to the tab that opened it. A screen that tries to open more than eight tabs has the extra ones closed, and the preview says so.

  • These work the same in the Stories view of a Storybook prototype, which is shown by the same browser.

  • Maximize fills the window with the app; Restore puts it back. The session is not reloaded either way, so you keep your place.

  • When the app behaves, Write Tests, beside Revise implementation, writes and runs the feature's tests. The button shows the run's progress, and once the run finishes, pass or fail, each scenario's result and trace are on the feature's Test Results tab. Starting it needs the Editor role.

  • Before a feature has a prototype or an implementation to run, Implementation offers Build on the target stack when the project builds designs on its stack, and is greyed out with the reason otherwise.

  • While some of the prototype's placeholders are still in the implementation, the view says how many, so you can watch them go. A feature cannot be merged while one remains, so an implementation run that has not replaced them all by the end of its review rounds fails, listing the ones left, rather than finishing; revise the implementation or continue the run.

  • A merged feature's Implementation runs the branch it was merged into: the repave branch when the project merges directly, or the base branch its pull requests target, as last fetched. That branch holds every merged feature, so every merged feature of the project shares the one environment. Restart picks up whatever has merged since it started. A merged feature is changed by reopening it, so Adjust and Revise implementation are off and say so.

  • Once a merged feature is reopened, its Implementation runs the feature's own branch again. Merging removed the feature's working copy, so the first start after the reopen recreates it from the branch the feature merged into, which holds all of the feature's work. Opening the feature in Repave IDE does the same.

  • Adjust works as it does on a target-stack prototype — on a branch that holds only its prototype, it is the prototype's Adjust, described under Giving feedback. Pin an element, say what should change, pin more on any screen, then Send to agent. Revise implementation does the same from a written instruction alone, with the feature's reference images. Either way an agent changes the feature's code on a branch of its own, updates the scenarios the change affects, runs them, has its work reviewed, and merges it into the feature's branch when its checks pass. A change no scenario describes — a colour, spacing, a layout — has no scenario to run, so a successful build is its check, and the review confirms nothing a scenario describes changed. With the browser on for the Implementation revision agent in Project Settings, which is its default, the agent starts the app and looks at the page it is changing. A feature built as part of a module is revised on the module's branch. The app on screen changes only when that lands, so you can keep using it — and keep pinning the next round — while the agent works.

  • When the revision lands, each comment says what happened to it: addressed, not addressed with the agent's reason, or claimed but not verified with the reviewer agent's reason. Adjust again for what was missed brings the rest back to send again. A revision that changed scenarios says so, because a changed scenario needs approving again. A revision that changed the dependencies restarts the environment to install them. If it fails, nothing is merged and your comments are kept.

  • Revising an accepted feature returns it to UAT for acceptance again, and the Revise dialog says so before you send. Revising is not available while the feature, its module or its verification is still running, or while another revision of it is; the controls say which. Revising needs the Editor role; a viewer can read a review but not send one.

  • Accessibility checks the screen you are on, exactly as it is now — signed in, mid-journey, with whatever you have opened or filled in — and lists what it finds beside the app. A clean result covers that state of that screen and nothing else. Select findings and Send to agent to have them fixed in the same kind of revision, or dismiss the ones you decide not to fix. When the implementation changes after a check, the findings say they are out of date.

  • If a start fails, the view shows why and the step it failed at, with its log, and Retry start tries again. Starting, retrying, restarting and stopping need the Editor role.

  • While it runs, its controls are in the Env menu beside the app's address bar. Restart starts it again from scratch, dependencies included, and Stop ends it. The menu says whose environment it is: a feature built as part of a module runs the module's, so restarting or stopping it does so for every feature in the module. Neither asks first, because Start undoes both.

  • Add test data…, first in the Env menu, fills the running implementation's database. Describe the rows you need, or upload a CSV, JSON, XLSX, SQL or dump file for an agent to map into the schema, then Generate data (or Inject data with files). The agent inserts in one transaction and commits what it inserted as a seed file on the feature's branch, so the next start has the same rows. The file travels with the branch, so the feature's UAT environment and, once merged, Main get the rows too when their UAT configuration applies seed files. When it finishes, the request shows what landed in each table and the app reloads to show it. You can close the dialog while it works. One test-data request runs at a time in a project, from here or from UAT Tools. The item is off, and says why, for an implementation that runs without a database. Adding test data needs the Editor role.

  • On a merged feature the item reads Reopen and add test data…. A merged feature runs the branch it was merged into, so its data needs a branch of its own: after one confirmation the feature is reopened, its implementation starts on the feature's own branch, and the test-data dialog opens when it is running. Once the data is committed, and as long as the feature's Gherkin did not change after the reopen, the feature is Implemented again, and Create PR (or Merge to Repave Branch, in a project that merges directly) ships the data like any other change. If the request fails, the feature stays reopened and Close puts it back to merged. A feature merged as part of a module keeps its test data on Main, in UAT Tools.

  • An implementation nobody has looked at for 30 minutes is stopped automatically, and the view says so when you come back.

  • A Storybook prototype is implemented from its Stories segment: Implement, beside Adjust and Accessibility, opens the usual implement dialog, which adds: "The prototype's components and stories become this feature's code. The agent builds the backend to return the data the stories fake." Clicking Implement is the acceptance — there is no separate accept step. When the implementation starts, the prototype it starts from is recorded as the approved one, with a screenshot of every story. The fake data is the contract the backend is built to: the agent makes each call return data of the shape the stories fake, and replaces the placeholders. The stories stay in your codebase, and the implementation renders every one of them again before it can finish: a story the implementation broke, or a To-Be scenario left without its story, fails the run and names the story, as a surviving placeholder does. A story is judged against how it rendered when the prototype was approved: a problem it already had then — a story that changes route on its own, say — does not fail the implementation; the run's log names it so you can fix it with Adjust. A feature implemented as part of a module is held to the same checks.

UAT Tools keeps its own environments, run from the project's UAT configuration, for formal acceptance. The two are separate: stopping one does not stop the other.

Giving feedback​

Pin it. Feedback attaches to the component it is about, on HTML, target-stack and Storybook prototypes, and several pinned problems can be reported from one session together. A pinned comment carries the context that a sentence in a chat box does not.

Everyone reviewing a prototype pins onto the same review, and Rebuild (or Update) sends every open comment in it, whoever wrote it. A comment someone else wrote carries their name. Anyone who can edit the project can delete any open comment, and Keep and Discard all act on all of them, but only a comment's author can change its wording. When the prototype changes after comments were written, the review asks you to keep the ones that still point at something before it rebuilds. On a target-stack prototype that happens whenever any feature in the project is built, since they share one app.

On a target-stack prototype, what you ask for does not stay in the preview. Once the Adjust run's code builds, the change is carried back to the design option the prototype was built from, and — only when it changes what the app does, such as a new rule or a different order — to the feature's To-Be scenarios. A changed scenario needs approving again; the others keep their approval. Each comment's result says what it changed, and a changed scenario opens side by side with what it said before.

A Figma design is changed in Figma itself, on the option's own page, and only after the code has built. While the run works you may see a copy of that page named "… · Adjust draft" in the file; the agent tries its change there, and the copy is removed when the run ends. The option's page is edited in place, so the layers the change does not touch keep your comments and links. If someone edits the page while the run works, it is left alone, and if Figma fails partway the page is put back as it was — or, when that cannot be confirmed, a copy of the page as it was is kept beside it, named "… · before Adjust", for you to compare. The connection to Figma set in Project settings must be able to edit the file; one that can only view it leaves the design as it was and says so.

On a Storybook prototype there is no separate design to carry a change back to: the code is the design. Adjust opens beside the story; Pick and click an element, and each pin shows the source file and line of what you picked (ClaimsToolbar.tsx:42) and the story it is in. A click often lands on something small inside what you mean — an icon inside a button — so the line above the comment box shows what you picked and the components around it ("Picked: svg ‹ Icon ‹ Button ‹ ClaimsToolbar"); choose one of the names to move the pin to it. When Repave cannot tell the exact line, the pin names only the component, and the agent looks there. A review can span the feature's stories: choose another story from the list above it and keep pinning. All the pins are one numbered list, in the order you placed them, and each story draws the markers of its own pins with the same numbers; click a pin's "in story: …" to show that story. Send to agent has the agent change the components and stories, going straight to each pin's line; the stories reload when it finishes, the result reads Prototype updated, and each pin's design line reads "The design is the code; nothing else to update." Scenario changes are proposed as on any other prototype.

Once implementation has started on the feature, its stories render the implemented components, so Adjust on a story changes the implementation itself, as Adjust on the Implementation segment does: the agent changes the feature's code on its own branch, and the stories reload when it finishes. Pins still name their story and source line. While it runs the review says "The agent is revising this feature." and you can keep pinning the next round; it merges when its checks pass, including every story still rendering, and the result reads Implementation revised.

Some changes are not carried back, and the result says why: a scenario that is already implemented (reopen it from the Gherkin tab), a feature that is already completed, scenarios or a design someone edited while the run worked, and a Figma file that could not be edited. Where the design does not show a change, implementation follows the preview for it rather than undoing it.

When a change fails, Show Errors says which way it failed. It sits in the panel's tab row, to the right of Remove prototype, and is hidden while there is nothing to read. A change whose code would not build is not committed: the prototype on the feature's branch stays as it was, the compiler's own output is shown for you to act on, and the attempt is left as uncommitted changes in the feature's worktree, where you can look at it in Repave IDE and the next change starts from it. Discard those changes in Repave IDE if you would rather start over. A change that could not start — its environment could not be started, so no agent ran — says why and that nothing was changed; deal with the cause and try it again.

A change builds on whatever is in the feature's worktree, including edits you have not committed in Repave IDE. Once it builds, the agent that made it commits it, together with those edits. What the build and the preview generate (installed dependencies, build output, downloaded tools) is not committed: the agent adds an ignore rule for it to .gitignore instead.

The design system​

A design system is produced automatically by the shell and prototype flows and written to DESIGN.md in the modernized codebase, together with the stylesheet tokens that encode it. That is what keeps the fifth feature looking like the first: agents read it rather than re-deciding typography and spacing per screen.

When the project merges through pull requests, both arrive as a pull request of their own, from the repave-platform/design-system branch, rather than being written to your base branch. On a project that combines several repositories, the stylesheet change goes to the repository it belongs to: it is made in a worktree named Repave: design system, which opens one pull request per repository it touches.

Accessibility​

Generated prototypes are checked for accessibility, deterministically, as they are produced. Whether that check gates a feature is a project setting — see Project settings.

Keeping a prototype honest​

  • When a feature's to-be scenario changes, its prototype can be regenerated, because a design for behaviour that has moved on is misleading.
  • Revising a target-stack prototype reconciles it to a design that has moved.
  • Adjusting a target-stack prototype updates the design, and the scenarios where behaviour changed, so the three never quietly disagree.
  • The target-stack prototype is the start of the feature's branch, built on the code that ships, so it never drifts away from it; implementing the feature replaces its placeholders in place.
  • A Storybook prototype is the code that ships, and its stories keep rendering through the implementation, so what was approved and what was built cannot drift apart.
  • Every prototype agent that can render its work looks at it, rather than reporting success on markup it never displayed.

Separately from individual features, the project has an application shell and a navigation map — the frame every screen sits in. The shell is designed like a feature's screens, in HTML or Figma, and you choose a design option on the Navigation & Shell page (a project using Storybook writes it as stories instead — see The shell in a Storybook project).

Implement shell on that page then builds the chosen design on your stack, checks that it builds and matches the design, and lands it on the base branch: as a pull request when the project merges through pull requests, or after you look at it running and click Merge when it merges directly. The agent that built the shell commits it, so the commit holds only the shell's own changes — never the dependencies the preview installed to run it. A shell whose commit picked them up anyway fails with the paths named and lands nothing; run Implement shell again. If the error says the shell branch already holds dependencies from an earlier run, an administrator must delete the repave-platform/app-shell branch before the shell can be implemented again. On a project that combines several repositories, the shell is not merged into the combined workspace, which is rebuilt from the repositories. It goes out as a pull request in each repository it changed, and the page lists them; the shell counts as merged once all of them have, and Merge is not offered. Once the shell is on the base branch, every feature built afterwards is built inside it.

In a new web application project, features cannot be implemented until the shell has merged, so every feature is built in the same frame; the implement button says so and links to the page. A batch job project has no user interface and so no shell, and is never held back by one. Implement shell runs once at a time, and is no longer offered once the shell has merged. Projects that existed before this was introduced are not held to it: their features can be implemented meanwhile, and are built without the shell until it merges.

The shell in a Storybook project​

In a project using Storybook the shell has no separate design either: it is your app's own components, with a Storybook story for each of its states, and every feature's stories render inside it. Navigation & Shell → Prototype offers Generate shell stories. An agent reads the To-Be navigation map and writes one story per state: Default, one ‹Entry› selected for each top-level entry of the map, Account menu open and Narrow screen. If your codebase already has a shell, the agent keeps it, changes it only where it differs from the To-Be map, and says what it changed; otherwise it writes one.

  • A shell that was already merged when the project switched to Storybook needs no stories: the card says it is already on your integration branch, and features' stories render inside it.
  • A shell designed in HTML or Figma before the switch is not recreated. The card shows it on a Design tab beside Stories, as it looked then, and Implement shell builds it — the UI check compares the result with it — and writes a story for each shell state in the same run. Generate shell stories stays available, if you would rather review the shell as stories first. Implement shell waits only for the To-Be navigation map, since the shell's states come from it.
  • Generate shell stories stays greyed out, with the reason under it, while Storybook is still being set up or its setup failed, and until the To-Be navigation map has been generated (on the To-Be tab). Generate Navigation & Shell on the To-Be tab does both: it generates the map and then the shell's stories.
  • While it runs, the card counts the stories that render so far, and you can leave the page. Every story is rendered before the shell is kept; one that does not render, or that tries to reach an outside address, fails the run and is named, with Try again.
  • The stories are listed in the same dropdown, one per shell state, each one streamed from the shell's own environment, with Adjust to pin comments on a story — as on a feature's stories — and send them to the agent. The sidebar then says Shell stories updated and how many comments were addressed.
  • Implement shell is offered once the shell has stories. It continues from them: the agent finishes the navigation wiring and keeps every story, which is rendered again before the shell can land; as for a feature, only a story that was fine when the stories were approved can hold it back. Clicking it records the stories as approved, with a screenshot of each. It then lands as described above, and features can be implemented once it has merged.