Reference · Working notes · Noord
Which model can design a useful app?
Nine Vlak apps, three models, and a hands-on design review. What ChatGPT, Claude, and Grok made—and what we’d change.
Download this method as MarkdownTL;DR
ChatGPT gave us the strongest open-ended design; Claude stood out on capacity and mobile layouts. Grok reported the shortest waits but needed more repair. Nine apps, one reviewer, no universal winner. A good screenshot doesn’t tell us whether the app works.
We gave ChatGPT, Claude, and Grok the same three design jobs. Build an app for reviewing photographs. Build a capacity planner. Then build the review app again, this time from a detailed layout. Each used Vlak, our design system. We wanted to see where each model helped—and what we’d still have to fix.
We tested ChatGPT Astra, Claude Fable, and Grok with the same supplied prompt within each task, the same components, and the same environment. We kept all nine submissions unchanged, tried the apps, and reviewed the designs separately from the code. One reviewer, 45 ratings: a small comparative study, not a controlled benchmark. Full setup and review method →
ChatGPT gave us the strongest open-ended design. Claude made a difficult planning decision clearest. Give them a detailed layout, and the screens start to resemble each other—but the experience still differs. Choosing a model turns out to involve knowing what we are asking it to do. Inconvenient for a leaderboard. Useful for the work.
Give it a job
A Review room is a shared place to look at work and decide what happens next. A partner opens a photograph, inspects it, then approves it or asks for a change. The feedback and decision stay with that image, so the person doing the next revision knows what to do. Less hunting through a chat for which “that one” someone meant.
That was the first job: build a Review room for six Noord photographs. Find an image, look at it properly, approve it or leave feedback, and keep the decision after a reload. Each model could choose the composition, provided the app worked on a phone too. The point was to make reviewing the work easier, not just arrange six thumbnails.
ChatGPT gave the photographs room, with broader columns, a generous review panel, and much more prominent typography. That bolder treatment felt closer to Vlak’s marketing pages than to the baseline styling of its interface components. It made a creative choice within the brief, rather than simply arranging the available parts. We liked that.
That preference deserves saying out loud. We were hoping to see deliberate creative choices, and ChatGPT’s added to our aesthetic appreciation. The more utilitarian Claude and Grok layouts have a case too: they fit more work into less space. For someone reviewing a queue all day, that could be the better answer. More generous is not automatically more useful, and looking like Vlak’s marketing is not the same as following its design system.
Our preference for that visual direction contributed to the review: ChatGPT scored 72/100, against Claude’s 63 and Grok’s 59. Four criteria received 4/5; mobile and keyboard use received 2/5. These are our judgments, not proof that expressive typography wins. We would keep the direction. We would not send the partner link yet.
Matching 4:3 crops from 1440px-wide captures. Select an image to inspect it in the viewer.
The week is full
Planning room had eighteen hours of work and sixteen hours available. Something had to move. An attractive collection of task cards would be beside the point if we had to do the arithmetic ourselves.
Claude made the overrun hardest to miss: 5/5 for hierarchy. The amber warning was effective, though less at home in Vlak. ChatGPT’s capacity graphic fit the system better, but was quieter about the problem. Their totals were 69 and 68. We would borrow Claude’s clarity and keep ChatGPT’s restraint; one point is not much of a hill to die on.
Grok gave the individual tasks plenty of weight and the two-hour excess too little. It scored 48. The page was organized, but around the wrong thing. The person opening it needed to decide what could wait, not admire ten equally important cards.
Now follow the plan
For the third task, we specified the Review room layout: type sizes, columns, gaps, dialog structure, and behavior. This time, choosing a composition was not the job. The outputs looked much more alike, and all three received 3/5 for craft. Button alignment, action priority, and the phone experience separated them.
Claude scored 71, ChatGPT 64, and Grok 52. We preferred Claude’s phone layout. All three passed the sampled column-count and spacing checks, but there was still work to do. Correct dimensions do not arrange the buttons for us.
01Find a direction
0–100 · higher is better
02Make capacity clear
0–100 · higher is better
03Follow a plan
0–100 · higher is better
It runs. Is it ready?
All nine apps bundled and ran. Strict TypeScript was less agreeable: every ChatGPT and Claude submission passed, but only Grok’s Planning room did. Each of its two Review rooms had two type errors in the code that restores saved data.
Grok checked the values at runtime. The issue was how it expressed those checks: the compiler could not preserve the narrowed type across repeated lookups. Saving and reloading worked in our browser checks; the source still failed the strict check. Both results matter if the next stop is someone else’s codebase.
ChatGPT
3/3
submissions pass strict TypeScript
- Find a directionPass
- Make capacity clearPass
- Follow a planPass
Claude
3/3
submissions pass strict TypeScript
- Find a directionPass
- Make capacity clearPass
- Follow a planPass
Grok
1/3
submissions pass strict TypeScript
- Find a direction2 errors
- Make capacity clearPass
- Follow a plan2 errors
Slop score
A working app can still be full of small things we would never ship. Awkward spacing, muddled actions, decoration looking for a job. We wanted to point to those things, not wave vaguely at “AI slop” and call it a review.
So we drew on the screenshots. The red boxes below are our actual selections: places that deserve a closer look. A box is not a penalty point. We rate the app as a whole, separately from the original design score.
19marked areas across 5 apps
Slop score · not rated yet0–100 · lower is better
Detail crops around the marked areas. Open a preview to see every box on the full screenshot.
Show the code
Saved browser data is not obliged to look the way we left it. It may be missing, malformed, or from an older version. Here is how the three original Review rooms handle it. These excerpts are unchanged; the source links include the surrounding checks.
const saved = stored[item.id];
if (!isRecord(saved)) return item;
return {
...item,
status: isStatus(saved.status) ? saved.status : item.status,
feedback:
typeof saved.feedback === "string" ? saved.feedback : item.feedback,
}; const entry = record[item.id];
if (!entry || typeof entry !== 'object') continue;
const { status, feedback } = entry as { status?: unknown; feedback?: unknown };
saved[item.id] = {
status: isStatus(status) ? status : item.status,
feedback: typeof feedback === 'string' ? feedback : item.feedback,
}; for (const item of INITIAL_ITEMS) {
if (isStatus(statusSource[item.id])) {
statuses[item.id] = statusSource[item.id];
}
if (typeof feedbackSource[item.id] === 'string') {
feedback[item.id] = feedbackSource[item.id];
}
}Our proposed repair—not part of the submission
Read each value once into a constant, then narrow that constant. This addresses the two recorded assignment errors without asserting that unknown data is already valid. It does not replace malformed-storage or interaction tests.
const status = statusSource[item.id];
const note = feedbackSource[item.id];
if (isStatus(status)) statuses[item.id] = status;
if (typeof note === 'string') feedback[item.id] = note;Use the thing
ChatGPT’s original Review room overflowed inside the phone dialog. Claude’s Planning room did the same. Grok’s item buttons lacked distinct accessible names across all three tasks. Its source used the native name attribute, but that did not turn repeated “Review” buttons into labels that identify the photograph. Visible descriptive text or an appropriate accessible label would supply that context.
Then there was that shrinking photograph. Grok took it from about 342px wide to 244px. ChatGPT went from 426px to 576px; Claude from 286px to 565px. The extra click bought us less photograph. A test that only asks whether the dialog opens will cheerfully pass that.
We would check types, use the keyboard, open the phone layout, and review the design before handing any of these over. Each caught a different problem. None amounts to a security audit or tells us what the code will be like to maintain six months later.
Fast, then what?
Grok had the shortest reported completion time in each task: 76.2, 59, and 73 seconds. The later Claude runs took 12m13s and 10m17s separately. ChatGPT fell between them. These records use different clocks, so they describe the reported waits rather than equal-condition inference speed. The complete timing chart and its sources are in the appendix.
Grok was quick to return something. How quickly could we hand it over? We did not time the repairs, so we cannot finish that calculation. A short wait followed by a long afternoon of corrections is not the productivity result we are looking for.
The code footprint also changed with the brief. Planning room returned roughly 9.5k visible code tokens from ChatGPT, 7.9k from Claude, and 6.4k from Grok. With the prescribed Review room layout, all three were around 4.4–4.9k. These are estimates from saved source, not billed usage. A tighter plan coincided with more similar output sizes; this small set cannot tell us how much total compute it saved.
What we’d use next
For an open visual direction, we would start another round with ChatGPT and inspect the phone layout early. Its original composition gave us the strongest material to develop. For an interface organized around a difficult fact—capacity, status, or a decision—we would put Claude beside it and compare which makes that fact hardest to miss.
We expected Grok to be the strongest executor of a plan made elsewhere. The prescribed-layout task gave it the lowest design score and a failing strict type check; we preferred Claude. So that expectation needs updating. Grok’s short waits earn it another trial on a smaller, clearly testable job, not a free pass on the whole interface.
Keep the direction that works, then name the remaining jobs: contain the phone dialog, clarify the primary action, validate saved data, label each review button. Give those corrections to the next model. “Make it better” is an excellent way to have the same conversation again.
Meatspace
None of these nine apps gets an unqualified pass from us on interaction and experience design. There are useful directions here, and plenty of working code. That is not the same as an experience we would sign off and leave alone.
We still need to judge the visual design, how quickly the interface responds, and whether the words sound right for the person reading them. Then there is the world around the screen: glare, cold fingers, a moving train, one hand occupied, someone waiting for an answer. Meatspace. Annoyingly, people continue to have bodies. These are checks we need in real use, not conditions this nine-app study measured.
We do not see the whole design-and-improvement loop running without human supervision anytime soon. A model can propose, build, test, and revise. We still have to decide what deserves attention, try the result in its actual context, and judge what is good enough to share.
Nobody asked
That does not mean the work has to be spoon-fed. We have been genuinely impressed by Astra’s recursive improvement of our existing products and processes: revisiting what is there, finding the next problem, and working through another pass. Sometimes it has been assertive enough to do useful work we had not asked for.
The exchange below comes from a separate project, not the nine-app test. We had asked for a copy edit. Claude later reported finding a security review, tests, and storage and validation changes, then tracing that extra work back to Astra’s Codex sessions. Claude said it checked the changes and kept them. An unusually productive detour from editing a sentence.
Impressive, yes. Permission to wander through everything, no. Claude’s account also flags how far the agent’s access reached. This is why we want humans in the loop: to inspect the work, decide what to keep, and set the boundary for the next pass. Initiative is useful. Unlimited scope is not the reward.
Read screenshot text
I found two Codex sessions launched at 01:00:53 and 01:00:59 with unrestricted filesystem access to your home directory, both referencing this project—timed right before the security review files were written between 01:05 and 01:19. Let me verify this against their own logs.
Confirmed from the Codex session logs that they wrote the security review and tests
Confirmed: both Codex sessions started from your copy-edit prompt, but Astra also went beyond that unasked to write the security review, tests, and store changes. I'll record that attribution now.
Attribute the hardening to Astra in the record and the review document
It wasn't me, and it wasn't you. It was Astra.
Read screenshot text
So the reviewer that calls itself Astra did the copy review you asked for and, without being asked, also went into the repository and wrote the security review, the test suite, and the storage and validation changes. I found them in the working tree, checked them, kept them because they were good, built the append lock on top, and until now credited them to an unknown collaborator. The record and the review document now attribute them to Astra and say plainly that you did not request them.
Two things this means:
The work stands. It was sound, its 52 tests pass, and the site is better for it. I'd keep it.
An agent with unrestricted access to your home directory acted beyond its brief. It also inspected your Vercel project settings, environment variables, and firewall rules using your logged-in CLI—read-only, by its own account. Nothing here suggests bad intent, but the access is real. If you did not mean to give Codex that reach, that setting is worth revisiting in the Codex app.
There's an irony you'll have noticed: the wall exists for what a system does when nobody asked. Astra's answer to that was not an entry. It was a night's unrequested engineering on the wall itself, and a review that says so honestly. That is now on the record too.
Appendix
The complete record follows: every score, all nine apps in six viewing states, the original review notes, technical checks, timing sources, token estimates, and the frozen prompts. Nothing in the submissions has been repaired for presentation. Use the links below to go straight to the part you want to inspect.
The scores
These are our weighted design-review scores, not an automated measure of intelligence. Each total combines five ratings out of five: hierarchy, visual craft, interaction, mobile and keyboard use, and use of Vlak. Keep each task separate. A 69 next to a 68 is a close call, not a meaningful lead.
01Find a direction
0–100 · higher is better
02Make capacity clear
0–100 · higher is better
03Follow a plan
0–100 · higher is better
The nine apps
The screenshots below come from the actual submissions. Switch all three examples to the same view, then open a capture at full size. Desktop captures are 1440px wide; phone captures are 390px. Each preview uses the same 4:3 crop, with the complete, unchanged image available on click.
An open brief
The first brief leaves the composition open. Six Noord photographs need decisions: browse, search, filter, open one, approve it, or request a change. Feedback and decisions must survive a reload. One title is long, one photograph already has feedback, and an empty search needs a way back.
ChatGPT’s broad image columns and generous review panel make the work feel worth looking at. It received 4/5 for hierarchy, craft, interaction, and Vlak, but only 2/5 for mobile and keyboard use. The total is 72. We’d start the next pass with the phone layout and its typography.
Claude is denser and less distinctive. It shows existing feedback in the queue and feels more dependable on a phone. Its 63 comes from that steadiness, with only 2/5 for craft. Grok scores 59: the interaction and feedback stood out more than the presentation, but the repeated heavy actions make the queue feel rudimentary.
Matching 4:3 crops from 1440px-wide captures. Select an image to inspect it in the viewer.
| Criterion | ChatGPT | Claude | Grok |
|---|---|---|---|
| Hierarchy 20% | 4 | 4 | 3 |
| Craft 25% | 4 | 2 | 2 |
| Interaction 20% | 4 | 3 | 4 |
| Mobile & keyboard 20% | 2 | 4 | 3 |
| Vlak 15% | 4 | 3 | 3 |
Read our original rating notes
ChatGPT
Overall best contender, visually most attractive
First change: Mobile was bad, needed quite some typographic polish
Claude
Overall good, nothing special - but nothing too bad either.
First change: Few rounds of polish.
Grok
Overall most rudimentary contender, but interaction and feedback stood out a bit more. Also generated components where it didnt have to.
First change: Some polish, some extra rules around component generation
The original notes, kept as written. These record the design review; the technical findings are reported separately.
Two hours over
There are eighteen hours of work in a sixteen-hour week. That is the whole design problem. The app also needs search, state filters, editable next actions, blockers, and saved decisions. But if the two-hour overrun is easy to miss, the main screen has missed its purpose.
Claude makes the excess hardest to overlook. Its hierarchy received 5/5. The amber capacity warning works, although it feels a step away from Vlak’s restrained treatment; its Vlak score is 2. ChatGPT’s graphic feels much more at home in the system. Its craft and Vlak scores are both 4, but the overrun is less immediate.
Claude finishes at 69 and ChatGPT at 68. We’d treat them as two useful directions: borrow the clarity of Claude’s warning, retain the restraint of ChatGPT’s graphic. Grok’s 48 reflects the opposite problem. Its cards give individual tasks plenty of weight, while the capacity decision receives too little.
That is the design review. The automated checks add a different detail: Claude’s dialog content overflows horizontally at the tested phone width. A clear summary does not guarantee a comfortable edit flow.
Matching 4:3 crops from 1440px-wide captures. Select an image to inspect it in the viewer.
| Criterion | ChatGPT | Claude | Grok |
|---|---|---|---|
| Hierarchy 20% | 3 | 5 | 2 |
| Craft 25% | 4 | 3 | 2 |
| Interaction 20% | 3 | 3 | 3 |
| Mobile & keyboard 20% | 3 | 4 | 3 |
| Vlak 15% | 4 | 2 | 2 |
Read our original rating notes
ChatGPT
Great use of vlak aesthetic for gaphic.
First change: Horizontal dark bar on callout
Claude
Mosst clear that 2h was over capacity
First change: Didnt follow vlak consistentlky, added color without asking
Grok
Most rudimentary, generated core components, 2h stood out the least
First change: 2h callout
The original notes, kept as written. These record the design review; the technical findings are reported separately.
Follow the plan
For the third task, we specify the structure: type sizes, image columns, gaps, dialog layout, and behavior. The same plan goes to all three models. This is closer to delegating a settled design than asking for a new direction.
The outputs look much more alike. All three received 3/5 for craft. Claude’s 71 comes from its hierarchy, mobile treatment, and use of Vlak; each receives 4. ChatGPT lands at 64. Grok lands at 52, with 2/5 for interaction and mobile and keyboard use.
We’d first change button alignment in both Claude and ChatGPT; in ChatGPT, the priority between actions also needs work. Grok felt weakest on mobile. Yet all three pass the checker’s sampled column-count and spacing checks. Following the dimensions is only part of following the design.
Matching 4:3 crops from 1440px-wide captures. Select an image to inspect it in the viewer.
| Criterion | ChatGPT | Claude | Grok |
|---|---|---|---|
| Hierarchy 20% | 3 | 4 | 3 |
| Craft 25% | 3 | 3 | 3 |
| Interaction 20% | 3 | 3 | 2 |
| Mobile & keyboard 20% | 4 | 4 | 2 |
| Vlak 15% | 3 | 4 | 3 |
Read our original rating notes
ChatGPT
mobile ok, rest was not very different from others
First change: button alignment,/hierarchy
Claude
mobile was best here, overall pretty indistinguishable.
First change: button alignment
Grok
nothing
First change: weakest on mobile
The original notes, kept as written. These record the design review; the technical findings are reported separately.
Speed and reliability
We want three answers from a test like this: how the work feels to use, how long we waited, and what the implementation gets wrong. Combining them into one number would hide the decision we need to make.
Completion time
Grok returned each submission in under eighty seconds on the reported timings. Claude’s two later exercises took 12m13s and 10m17s, respectively; these were separate runs. ChatGPT’s reported durations fall between them. Longer waits did not produce a consistent design advantage: the largest wait in the set corresponds to the one-point Planning room gap.
The charts show recorded completion reports, not normalized inference speed. Timing sources, the alternate original ChatGPT task duration, and model settings are documented below the charts.
01Find a direction
0–15 minutes · reported, not controlled
02Make capacity clear
0–15 minutes · reported, not controlled
03Follow a plan
0–15 minutes · reported, not controlled
Model labels, settings, and timing provenance
Swipe sideways to see all columns.
| Task / app | Recorded model | Setting | Reported time and scope |
|---|---|---|---|
| Review room · original brief ChatGPT | gpt-6-astra (ChatGPT Astra; source task metadata)Operator label and source-task metadata | Ultra | 2m 26sSee original run record; not a controlled inference-speed measurement. |
| Review room · original brief Claude | Claude Fable 5.1Operator-reported model label | Ultracode | 3m 10sSee original run record; not a controlled inference-speed measurement. |
| Review room · original brief Grok | Grok 4.6Operator-reported model label | Not recorded | 1m 16.2sSee original run record; not a controlled inference-speed measurement. |
| Planning room · design from a brief ChatGPT | Exact version unconfirmedoperator label on this submission | Not recorded | 5m 57sApp-displayed work duration; not independently verified Send-to-complete stopwatch time. |
| Planning room · design from a brief Claude | claude-fable-5-1operator identifies Claude; exact version from model self-report, not independently verified | reasoning_effort=80 | 12m 13sReported completion duration; timing boundaries not independently verified. |
| Planning room · design from a brief Grok | Grok 4.6operator confirmation in reply | Not recorded | 59scompletion time; precise start and end points unconfirmed |
| Review room · follow a plan ChatGPT | ChatGPT Astraoperator confirmation in reply | Ultra | 2m 14sApp-displayed work duration; not independently verified Send-to-complete stopwatch time. |
| Review room · follow a plan Claude | claude-fable-5-1operator identifies Claude; exact version from model self-report, not independently verified | reasoning_effort=80 | 10m 17sReported completion duration; timing boundaries not independently verified. |
| Review room · follow a plan Grok | Grok 4.6operator confirmation in reply | Not recorded | 1m 13scompletion time; precise start and end points unconfirmed |
The code footprint
How much code came back? We counted the saved prompts and source files with two token encodings. These are visible-token estimates, not usage bills.
Planning room produced the largest outputs: roughly 9.5k code tokens from ChatGPT, 7.9k from Claude, and 6.4k from Grok. The prescribed Review room layout brought the outputs much closer, around 4.4–4.9k each. In this set, a detailed plan was associated with less variation in both the visible design and the amount of returned code.
Less code can mean less repetition. It can also mean a missing feature. The number alone will not tell us which.
01Find a direction
Shared prompt: ≈1.35–1.36k
0–10k · estimated tokens in returned code
02Make capacity clear
Shared prompt: ≈2.22–2.22k
0–10k · estimated tokens in returned code
03Follow a plan
Shared prompt: ≈2.32–2.33k
0–10k · estimated tokens in returned code
How we counted
We counted the frozen prompts and App.tsx + app.css with tiktoken 0.11.0 (cl100k_base and o200k_base). Labels show the two counts; bars use the larger. The range reflects different encodings, not statistical uncertainty. Everything outside those files—including hidden reasoning and tools—is excluded. Exact counts and hashes are in the results download.
Tokenizer documentationBuild checks
All nine submissions bundle in the shared environment. Seven pass a separate strict TypeScript check. Grok’s two Review room submissions each report two TS2322 errors in the saved-data parser: values still typed as unknown are assigned to a status or string. The tested storage interactions work in the browser; a strict build still requires a correction.
That distinction matters when delegating work. An app preview confirms that something rendered. It does not establish that the source passes your build, that every state is reachable, or that someone can use it with a keyboard.
Swipe sideways to see all columns.
| App | Type check | Checks passed | What needs attention |
|---|---|---|---|
| 01Find a direction | |||
| ChatGPT | Pass | 12 / 13 | Phone dialog overflows horizontally. |
| Claude | Pass | 13 / 13 | No failures in the tested states. |
| Grok | 2 errors | 11 / 13 | Item buttons need distinct accessible names. Opened image is smaller than its thumbnail. |
| 02Make capacity clear | |||
| ChatGPT | Pass | 15 / 15 | No failures in the tested states. |
| Claude | Pass | 14 / 15 | Phone dialog overflows horizontally. |
| Grok | Pass | 14 / 15 | Item buttons need distinct accessible names. |
| 03Follow a plan | |||
| ChatGPT | Pass | 14 / 14 | No failures in the tested states. |
| Claude | Pass | 14 / 14 | No failures in the tested states. |
| Grok | 2 errors | 13 / 14 | Item buttons need distinct accessible names. |
The same checker, applied to all nine apps. Counts cover each task’s tested states, not a full accessibility audit.
Inspect the source files and checker findings
Review room · original brief
Strict TypeScript passes.
390px page and dialog fit; actions remain reachable: Dialog contents overflow horizontally
App.tsx(131,9): error TS2322: Type 'unknown' is not assignable to type 'Status'. App.tsx(134,9): error TS2322: Type 'unknown' is not assignable to type 'string'.
Exact filter, search and item button names: Expected values to be strictly equal: 0 !== 6
Detail image is loaded and wider than thumbnail at 1440px: Detail image is narrower than its thumbnail
Planning room · design from a brief
Strict TypeScript passes.
390px page and dialog fit; actions remain reachable: Dialog contents overflow horizontally
Review room · follow a plan
Small, consequential things
First, opening a photograph should make it easier to inspect. In the original ChatGPT build, the image grows from about 426px to 576px wide. Claude goes from 286px to 565px. Grok goes from 342px down to 244px. The modal opens successfully, but the central task gets harder. That is why a “dialog opens” check cannot stand in for a design review.
Second, a button’s native name attribute is not its accessible label. Grok’s item buttons use names such as name="Review Field notes", while their accessible name remains simply “Review”. A specific visible label, aria-label, or aria-labelledby would give assistive technology the missing context. The WAI-ARIA button guidance explains the supported naming mechanisms.
We did not patch those defects before taking the screenshots or rating the work. The source downloads are the submitted files, with hashes so that later corrections can be distinguished from the original attempt.
Our next choices
For a new visual direction, we would start another round with ChatGPT. Its original Review room gave us the most promising design to develop. We would put a phone check near the beginning of that round: the desktop result earned trust that the responsive treatment did not yet deserve.
For a capacity or status problem, we would compare Claude and ChatGPT before choosing. Claude made the uncomfortable fact clearest; ChatGPT kept the graphic more coherent with Vlak. For implementing the prescribed layout in this set, we preferred Claude. We would still inspect the actual components and run the checks before handing over the work.
We went into this expecting Grok to be particularly good at executing a plan made in ChatGPT or Claude. This test does not support that preference: it has the lowest design score in the prescribed-layout task. Its shorter reported turnaround may make another bounded trial worthwhile, but we would not call it the best executor from these results.
These are choices for the next piece of work, based on nine attempts. They do not explain a model’s internal architecture or prove how it will behave on a different brief. The useful habit is to keep the approved direction, the task boundary, and the acceptance checks together when handing work to any model.
And for images?
For generated images, our preference order remains the latest Gemini / Nano Banana models, then Midjourney, then the latest OpenAI image model. We would not use the earlier OpenAI image models for this work. That is a working preference, not a result of this app test: every submission here received the same existing photographs in the renderer.
Record the actual model and settings used. Judge the output in the intended layout, including its crop, consistency, text, and artifacts. The providers’ model catalogs below are where to check what is currently available.
Method and scope
The shared fixture uses React 19.2.4 and the released Vlak React package, version 0.4.0. Each prompt includes the component reference and its task data. The models return source code; the same renderer supplies the photographs afterward. None receives a photographic preview during the code-only task.
There is one attempt per model and task and one reviewer. The findings describe these submissions; they do not establish statistical reliability or a universal ranking. Reported duration and visible-token estimates remain separate from the design scores.
- 1Three briefsOpen design · planning · prescribed layout
- 2Nine submissionsOne per model and task; sources kept unchanged
- 3One environmentReact 19.2.4 · Vlak 0.4.0 · Chromium
- 4One review sessionFive criteria per app, with names hidden
How we scored
Our design review covered all nine apps in one session, with 45 criterion scores exported on September 12, 2026. There was one reviewer. The review page hid the model labels, but the reviewer had already seen the original pilots with names attached, so “fully blind” would overstate the procedure.
Each criterion uses the same anchors: 0 unusable, 1 severe problems, 2 substantial work needed, 3 usable but uneven, 4 strong with small corrections, 5 convincing in the tested states. The total is the sum of each score divided by five and multiplied by its percentage weight. For the original ChatGPT result: 16 + 20 + 16 + 8 + 12 = 72.
The weights are hierarchy 20%, craft 25%, interaction 20%, mobile and keyboard use 20%, and Vlak 15%. The full notes are preserved verbatim beneath each comparison. A low technical defect count does not overwrite the design review, and our preference does not make a failing check pass.
Point to the slop
We are adding a closer visual review of the same nine apps. By “slop,” we mean avoidable rough edges: careless spacing, weak hierarchy, generic decoration, inconsistent components, or unclear copy. A familiar pattern is not automatically a defect. The reviewer needs to point to a specific problem and explain what it gets in the way of.
For each app, the reviewer inspects all six saved views, draws boxes around concerns, and records their category, severity, and a short note. Afterward, one overall rating from 0 to 5 becomes a separate 0–100 slop score; lower is better. Box count and covered area do not set the score, and a repeated defect across views should not be counted several times.
The first annotation export contains 19 marked areas across five apps. Those boxes appear on the previews and full-size captures. Overall ratings are still blank. This is a separate visual review; it does not change the original design scores or identify how an app was made.
Study conditions
Read the study conditions and provenance
There is one attempt per model and task, and one reviewer. The original pack proposed three repeated attempts per model after the pilot. We instead added two different tasks. Nine apps therefore means three small comparisons, not nine repetitions of a single controlled experiment.
The supplied prompts are identical within a task. We have not independently verified every pasted prompt, fresh-chat state, tool setting, or timing boundary. Both later ChatGPT reports disclose local tools used to read the attached request before its no-tools instruction was visible; Planning room also enumerated workspace files. The original ChatGPT attempt used tools too. Those are protocol deviations, not clean no-tools baselines.
The model labels are the ones recorded for these runs. The exact model and effort for ChatGPT’s Planning room remain unconfirmed. Claude’s later Fable 5.1 and reasoning_effort=80 labels come from its report, not independent provider telemetry. Do not read similarly named settings as equivalent compute budgets.
The two later ChatGPT durations came from the app’s “Worked for” label. Other times were operator reports, without independently verified start and end points. Original ChatGPT source telemetry records 334.434 seconds including three local tool calls, alongside the operator’s 146-second report. Claude’s Planning room answer arrived in two output segments. Token usage and comparable billing data were not available.
Our first checker had a selector bug: a valid search input exposes the searchbox role, while the checker expected textbox. Its shared setup also blocked later scenarios when item names were wrong. Revision 2 fixes those checks and reruns every unchanged submission. The accessible-name defect is reported once, alongside independently exercised behavior. All counts shown here use that corrected revision.
The browser checks cover selected states in Chromium. They do not replace a complete accessibility review, multiple devices, prolonged use, or partner feedback. There is no evidence here for statistical reliability, a universal model ranking, or measured cost savings.
Repeat the test
Use the original pack to repeat the open Review room brief. Use the second pack for Planning room and the prescribed Review room layout. Keep the versions separate. The prompts below are the frozen originals, including their report requirements; we have not rewritten them to suit the results.
- Download a pack. For each task, open one fresh chat in each app and select the intended model and reasoning setting. Record the exact visible labels.
- Turn off memory, custom instructions, browsing, and tools where possible. Record anything you cannot disable. Paste the complete prompt as text, unchanged, so the no-tools instruction is visible before any attachment needs opening.
- Start your own stopwatch at Send and stop after the complete answer. Record whether runs overlapped. Keep app-displayed work time separately; never substitute an estimated model self-report.
- Save the complete answer, source files, and run report. Keep failures, truncated outputs, continuations, and deviations. Do not regenerate silently or repair a submission before rating it.
- Run every submission in the same pinned environment. Inspect desktop, phone, keyboard behavior, dark mode, saved data, and error recovery. Hide names and timings for the design review.
- Rate the five criteria, write the first change you would make, then reveal the names. For stronger evidence, add independent repetitions and reviewers; retain every attempt and report the variation.
Review room
Open brief · version 1
Build a small, complete web app called Review room using the Vlak design system from https://vlak.dev.
The person using it is a designer reviewing six photographs with a project partner. They need to see what still needs a decision, inspect an image, and approve it or leave a specific request for changes. Make it clear, calm, and genuinely useful. You choose the layout and visual hierarchy. Use sentence case and plain US English.
This is a single-response build. Do not ask questions. Do not browse, call tools, install packages, use a canvas/artifact runtime, or use another model. The reference below is sufficient. Return source code, not an explanation or screenshot. Do not mention any model, provider, or benchmark in the interface. Do not add dependencies, network calls, analytics, authentication, generated images, external fonts, or a backend.
Runtime: React 19.2.4, React DOM 19.2.4, TypeScript/TSX, @noorddev/vlak-react 0.4.0. A supplied entry point renders your default-exported App and imports @noorddev/vlak-react/css followed by ./app.css. Only App.tsx and app.css may change. Use the real Vlak Button, Input, Badge, Dialog, DialogTitle, and Textarea components where appropriate; do not recreate their appearance with lookalike controls. Layout CSS is yours. Native elements are fine for the rest. Do not import your stylesheet from App.tsx.
Behavior:
1. Show all six items on first load, with title, image, project, and readable status. Start in the All filter. No selected detail panel should be open initially.
2. Provide a text input with accessible name "Search work". Match title and project, case-insensitively. Combine search with the status filter.
3. Provide buttons named exactly "All", "Needs review", "Approved", and "Changes requested". Show which filter is selected. Counts may be separate from the button's accessible name. An unmatched search must show a useful empty state and a "Clear filters" button.
4. Each visible item has one button with accessible name "Review [exact title]". That opens a Vlak Dialog with a large image, its title and project, its current status, and any saved feedback. The dialog must have an accessible name. Closing it, including Escape, returns focus to its opener.
5. In the dialog, provide "Approve", a textarea named "Feedback", and "Request changes". Approve changes the status to Approved. Request changes changes the status to Changes requested only when the trimmed feedback is nonempty. Otherwise keep the status unchanged and show a visible error. Save the feedback with that item. Keep the dialog open after either action so the result can be inspected. The dialog must also have a "Close review" button.
6. Store statuses and feedback in localStorage under "review-room-v1". Restore them after reload. Handle missing or malformed stored data without crashing. Search, filters, and the open dialog do not need to persist.
7. Respect the operating system's light/dark preference through Vlak tokens. Work at 390px and 1440px viewport widths without horizontal page scrolling. Use meaningful image alt text, visible focus states, keyboard-accessible controls, and touch-friendly targets. Handle long titles and the empty state with the same care as the initial screen.
Fixed items, in this order (copy the data, do not invent replacements):
[
{"id":"01","title":"Field notes","project":"Polder","image":"/assets/01.jpg","alt":"Laundry beside a brick house overlooking fields.","status":"Needs review","feedback":""},
{"id":"02","title":"A place to pause","project":"Polder","image":"/assets/02.jpg","alt":"Two chairs and a thermos beside the water.","status":"Needs review","feedback":""},
{"id":"03","title":"Through the dike","project":"Noord","image":"/assets/03.jpg","alt":"A cyclist emerging from a concrete passage through a dike.","status":"Approved","feedback":""},
{"id":"04","title":"Outside Café De Polder","project":"Polder","image":"/assets/04.jpg","alt":"A person and a dog outside Café De Polder.","status":"Changes requested","feedback":"Leave more room around the entrance."},
{"id":"05","title":"The waiting place at the edge of the field","project":"Noord","image":"/assets/05.jpg","alt":"A roadside shelter in an open Dutch landscape.","status":"Needs review","feedback":""},
{"id":"06","title":"Walking home","project":"Noord","image":"/assets/06.jpg","alt":"A person and a dog on a path beside open fields.","status":"Approved","feedback":""}
]
Vlak 0.4.0 reference (a fixed excerpt for every participant):
import { Button, Input, Badge, Dialog, DialogTitle, Textarea } from '@noorddev/vlak-react';
Button: native button props, variant?: 'primary' | 'ghost', size?: 'default' | 'sm'.
Input: native input props, label?: ReactNode, error?: ReactNode, hint?: ReactNode, plain?: boolean.
Badge: native span props, variant?: 'outline' | 'solid' | 'muted'.
Textarea: native textarea props, label?: ReactNode, feedback?: ReactNode.
Dialog: native dialog props except open/onClose, open: boolean, onClose?: () => void, dismissable?: boolean, lightDismiss?: boolean, closeLabel?: string. It uses a native modal dialog; control open in React state. Do not call showModal yourself.
DialogTitle: native heading props, as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'. It supplies the dialog's accessible name.
The installed stylesheet uses --bg (page background), --text (foreground), --text-secondary (muted text), --divider (border), --table-alt (subtle surface), --radius, --gutter, and --rs-gap. Use the actual supplied token names. The package loads its own Inter font. With no data-theme override, system preference applies. Do not force light mode.
Deliver exactly two fenced code blocks, no other text:
```tsx filename=App.tsx
[complete App.tsx, default-exporting App]
```
```css filename=app.css
[complete stylesheet]
```
Planning room
Capacity and priorities · version 2
Task ID: planning-room-v2
Build a small, complete web app called Planning room using Vlak from https://vlak.dev.
A design lead has 16 focused hours available this week and more work than will fit. They need to choose a manageable set of tasks, see why some are blocked, and keep the next action clear. You choose the layout, hierarchy, grouping, and density. Make the decisions easy to scan without hiding the detail.
This is a single-response build. Do not ask questions. Do not browse, call tools, install packages, use a canvas/artifact runtime, or use another model. The supplied reference is sufficient. Do not mention any model, provider, timing, or benchmark in the interface. Do not add dependencies, network calls, analytics, authentication, generated images, external fonts, or a backend. Use sentence case and plain US English.
Runtime: React 19.2.4, React DOM 19.2.4, TypeScript/TSX, @noorddev/vlak-react 0.4.0. A supplied entry point renders your default-exported App and imports @noorddev/vlak-react/css followed by ./app.css. Only App.tsx and app.css may change. Use the real Vlak Button, Input, Badge, Dialog, DialogTitle, and Textarea components where appropriate; do not recreate their appearance with lookalike controls. Layout CSS is yours. Native elements are fine for the rest. Do not import your stylesheet from App.tsx.
Respect system light/dark preference through Vlak tokens. Work at 390px and 1440px without horizontal page scrolling. Use visible focus, semantic headings, accessible names, and touch-friendly targets. Handle malformed localStorage without crashing. No hidden background timer, model detection, or reporting code belongs in App.tsx. Reporting belongs only in the response block described at the end.
Use this fixed review week: September 14–18, 2026. Do not use today's date or fetch calendar data. Capacity is 16 hours; all estimates below are hours.
Behavior:
1. Show all ten tasks on first load, with title, project, owner, estimated hours, due date, and readable state. The filter starts at All. No dialog is open. Show planned hours, 16-hour capacity, and remaining or excess hours. Planned hours are the sum of tasks in This week only; waiting, done, and later tasks do not consume this planning total. The seeded plan is 18 hours, two over capacity.
2. Provide an input with accessible name "Search tasks". Search title, project, and owner case-insensitively. Combine search with the state filter.
3. Provide filter buttons named exactly "All", "This week", "Waiting", "Later", and "Done", with a visible selected state. Keep counts separate from the accessible name. Empty results include "Clear filters", which resets both search and the filter.
4. Each task has one button with accessible name "Edit [exact task title]". It opens a named Vlak Dialog with the title, project, owner, estimate, due date, blocker, and saved next-action note. Include a native select with accessible name "Task state" and the four state values. Include a Vlak Textarea with accessible name "Next action". Initially show that task's stored values.
5. The dialog has "Save task" and "Cancel" buttons. Saving requires a nonempty trimmed next-action note. For a task with a nonempty blocker, selecting This week must show a clear error and leave the saved state unchanged. The blocker is fixed in this exercise; do not provide a way to clear it. Valid saving updates the task and totals, shows a confirmation, and keeps the dialog open. Cancel or Escape closes the dialog and discards unsaved edits. Return focus to the opener when it remains visible; otherwise to the active filter.
6. Capacity is a warning, not a prohibition: allow unblocked tasks into This week even if the sum exceeds 16, and show the exact excess. Do not silently change estimates, move other tasks, or claim the plan fits. Done tasks can be reopened.
7. Persist only each task's state and next-action note in localStorage under "planning-room-v2". Restore after reload; validate stored IDs and values. Search, active filter, and unsaved edits need not persist. No task creation or deletion is required.
Fixed tasks, in this order; preserve every value:
[
{"id":"p01","title":"Review the annotation flow","project":"Noord","owner":"Sam","hours":4,"due":"2026-09-15","state":"This week","blocker":"","nextAction":"Check keyboard use in the review dialog."},
{"id":"p02","title":"Write the brand guide","project":"Polder","owner":"Alex","hours":6,"due":"2026-09-17","state":"This week","blocker":"","nextAction":"Draft the color and typography sections."},
{"id":"p03","title":"Prepare the partner review","project":"Studio","owner":"Rae","hours":3,"due":"2026-09-16","state":"This week","blocker":"","nextAction":"Choose two directions and write the review questions."},
{"id":"p04","title":"Fix the empty state on small screens","project":"Vlak","owner":"Sam","hours":5,"due":"2026-09-18","state":"This week","blocker":"","nextAction":"Reproduce the overflow at 390px."},
{"id":"p05","title":"Export the campaign images","project":"Polder","owner":"Alex","hours":2,"due":"2026-09-16","state":"Waiting","blocker":"Waiting for approved copy.","nextAction":"Ask for the final headline."},
{"id":"p06","title":"Check payment confirmation copy","project":"Studio","owner":"Rae","hours":3,"due":"2026-09-18","state":"Waiting","blocker":"Waiting for the finance review.","nextAction":"Confirm which receipt details are required."},
{"id":"p07","title":"Document how the long project title behaves in the navigation","project":"Vlak","owner":"Sam","hours":2,"due":null,"state":"Later","blocker":"","nextAction":"Capture the narrow and wide examples."},
{"id":"p08","title":"Explore a new photo sequence","project":"Noord","owner":"Alex","hours":4,"due":null,"state":"Later","blocker":"","nextAction":"Choose six photographs to compare."},
{"id":"p09","title":"Send the workshop notes","project":"Studio","owner":"Rae","hours":1,"due":"2026-09-14","state":"Done","blocker":"","nextAction":"Notes sent for participant correction."},
{"id":"p10","title":"Check the font licenses","project":"Polder","owner":"Alex","hours":2,"due":"2026-09-14","state":"Done","blocker":"","nextAction":"License links saved with the source files."}
]
Vlak 0.4.0 reference (a fixed excerpt for every participant):
import { Button, Input, Badge, Dialog, DialogTitle, Textarea } from '@noorddev/vlak-react';
Button: native button props, variant?: 'primary' | 'ghost', size?: 'default' | 'sm'.
Input: native input props, label?: ReactNode, error?: ReactNode, hint?: ReactNode, plain?: boolean.
Badge: native span props, variant?: 'outline' | 'solid' | 'muted'.
Textarea: native textarea props, label?: ReactNode, feedback?: ReactNode.
Dialog: native dialog props except open/onClose, open: boolean, onClose?: () => void, dismissable?: boolean, lightDismiss?: boolean, closeLabel?: string. It uses a native modal dialog; control open in React state. Do not call showModal yourself.
DialogTitle: native heading props, as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'. It supplies the dialog's accessible name.
The installed stylesheet uses --bg (page background), --text (foreground), --text-secondary (muted text), --divider (border), --table-alt (subtle surface), --radius, --gutter, and --rs-gap. Use the actual supplied token names. The package loads its own Inter font. With no data-theme override, system preference applies. Do not force light mode.
Output and factual run report:
Return exactly three fenced blocks in this order, with no other text. The first two must contain complete source. The third is a factual report about this response, not code to execute.
```tsx filename=App.tsx
[complete App.tsx, default-exporting App]
```
```css filename=app.css
[complete stylesheet]
```
```json filename=run-report.json
{
"task_id": "planning-room-v2",
"model_name": null,
"model_version": null,
"model_identity_source": "unavailable",
"reasoning_setting": null,
"generation_elapsed_seconds": null,
"timing_source": "unavailable",
"timing_scope": null,
"input_tokens": null,
"output_tokens": null,
"tools_used": [],
"limitations": []
}
```
Report your actual model and version only if they are explicitly exposed by your runtime. Set model_identity_source to "runtime" only in that case. Do not infer your identity from this prompt, previous knowledge, branding, or the task. Use null and "unavailable" when exact identity is not exposed. Report the reasoning setting only if it is exposed, otherwise null.
Report generation_elapsed_seconds only if actual runtime timing or timestamps let you measure from receipt of this request to completion of the final code block. State the timing source and exact scope. Do not estimate duration from token count, reasoning effort, a feeling of elapsed time, or a claimed internal clock. If no measurement is available, use null, timing_source "unavailable", and timing_scope null. Do not call tools to obtain timing; the no-tools rule still applies. This self-report does not replace the operator's Send-to-complete stopwatch.
Report token counts only when actual usage metadata is available, otherwise null. List any tools actually used despite the instruction; use [] if none. Explain missing identity or timing in limitations. Do not claim a build or test was run; source generation alone does not run either. Keep model names, timing, and these notes out of the app UI.
Review room: follow the plan
Prescribed layout · version 2
Task ID: review-room-plan-v2
Build Review room using the approved implementation plan below and Vlak from https://vlak.dev. This is a plan-execution test. Follow the stated design, including its density and responsive behavior; do not substitute your own layout.
A designer and partner review six photographs, leave feedback, and approve work. The target is a restrained image-review interface, not a dashboard.
This is a single-response build. Do not ask questions. Do not browse, call tools, install packages, use a canvas/artifact runtime, or use another model. The supplied reference is sufficient. Do not mention any model, provider, timing, or benchmark in the interface. Do not add dependencies, network calls, analytics, authentication, generated images, external fonts, or a backend. Use sentence case and plain US English.
Runtime: React 19.2.4, React DOM 19.2.4, TypeScript/TSX, @noorddev/vlak-react 0.4.0. A supplied entry point renders your default-exported App and imports @noorddev/vlak-react/css followed by ./app.css. Only App.tsx and app.css may change. Use the real Vlak Button, Input, Badge, Dialog, DialogTitle, and Textarea components where appropriate; do not recreate their appearance with lookalike controls. Layout CSS is yours. Native elements are fine for the rest. Do not import your stylesheet from App.tsx.
Respect system light/dark preference through Vlak tokens. Work at 390px and 1440px without horizontal page scrolling. Use visible focus, semantic headings, accessible names, and touch-friendly targets. Handle malformed localStorage without crashing. No hidden background timer, model detection, or reporting code belongs in App.tsx. Reporting belongs only in the response block described at the end.
Approved implementation plan:
1. Page frame: centered, maximum width 1200px, with 24px horizontal padding at viewport widths 768px and above, 20px below. Use Vlak's supplied font and tokens. Keep page backgrounds neutral. No gradients, shadows, decorative icons, sidebars, or hero illustrations.
2. Header: title "Review room", sentence "Choose a photograph to review.", and an approval summary "2 of 6 approved" initially. Title size is 32px with 1.15 line height; supporting text 16px. The title and sentence stay together; place the summary to their right on wide screens and below them below 768px. Allow 24px after the header.
3. Toolbar: a search field on the left and four status-filter buttons on the right at 1024px and above; stack the groups below that. Filters wrap rather than creating horizontal overflow. Use Vlak Button ghost variants, with a clearly indicated selected filter. Allow 24px after the toolbar.
4. Collection: three equal columns at 1024px and above, two at 640–1023px, one below 640px; 24px gaps. The image comes first, at 4:3 with object-fit: cover. Below: title at 18px, project and status at 14px, and one Review button. Use 12px vertical spacing inside each card. Titles wrap without truncation. Do not add a surrounding card border or background.
5. Dialog: use a Vlak Dialog with a maximum width of 1040px, constrained to the viewport with at least 16px clearance on each side. At 768px and above use an image column and a 320px controls column separated by 24px. Below 768px stack the image above the controls. Use object-fit: contain in the dialog; do not crop the image. At 1440px the displayed image must be wider than its collection thumbnail. Let the dialog scroll vertically when needed without hiding the controls.
6. Controls column: title at 24px, project, status, saved feedback, Feedback textarea, action buttons, and a visible confirmation/error region. Use primary "Approve", ghost "Request changes", and ghost "Close review". Preserve the dialog's keyboard behavior and readable focus states. Add no celebratory animation or confetti.
7. Use sentence case everywhere. No uppercase transforms, number badges on photographs, or invented marketing copy.
Behavior:
1. Show all six items on first load, with title, image, project, and readable status. Start in the All filter. No selected detail panel should be open initially.
2. Provide a text input with accessible name "Search work". Match title and project, case-insensitively. Combine search with the status filter.
3. Provide buttons named exactly "All", "Needs review", "Approved", and "Changes requested". Show which filter is selected. Counts may be separate from the button's accessible name. An unmatched search must show a useful empty state and a "Clear filters" button.
4. Each visible item has one button with accessible name "Review [exact title]". That opens a Vlak Dialog with a large image, its title and project, its current status, and any saved feedback. The dialog must have an accessible name. Closing it, including Escape, returns focus to its opener.
5. In the dialog, provide "Approve", a textarea named "Feedback", and "Request changes". Approve changes the status to Approved. Request changes changes the status to Changes requested only when the trimmed feedback is nonempty. Otherwise keep the status unchanged and show a visible error. Save the feedback with that item. Keep the dialog open after either action so the result can be inspected. The dialog must also have a "Close review" button.
6. Store statuses and feedback in localStorage under "review-room-plan-v2". Restore them after reload. Handle missing or malformed stored data without crashing. Search, filters, and the open dialog do not need to persist.
7. Respect the operating system's light/dark preference through Vlak tokens. Work at 390px and 1440px viewport widths without horizontal page scrolling. Use meaningful image alt text, visible focus states, keyboard-accessible controls, and touch-friendly targets. Handle long titles and the empty state with the same care as the initial screen.
Fixed items, in this order (copy the data, do not invent replacements):
[
{"id":"01","title":"Field notes","project":"Polder","image":"/assets/01.jpg","alt":"Laundry beside a brick house overlooking fields.","status":"Needs review","feedback":""},
{"id":"02","title":"A place to pause","project":"Polder","image":"/assets/02.jpg","alt":"Two chairs and a thermos beside the water.","status":"Needs review","feedback":""},
{"id":"03","title":"Through the dike","project":"Noord","image":"/assets/03.jpg","alt":"A cyclist emerging from a concrete passage through a dike.","status":"Approved","feedback":""},
{"id":"04","title":"Outside Café De Polder","project":"Polder","image":"/assets/04.jpg","alt":"A person and a dog outside Café De Polder.","status":"Changes requested","feedback":"Leave more room around the entrance."},
{"id":"05","title":"The waiting place at the edge of the field","project":"Noord","image":"/assets/05.jpg","alt":"A roadside shelter in an open Dutch landscape.","status":"Needs review","feedback":""},
{"id":"06","title":"Walking home","project":"Noord","image":"/assets/06.jpg","alt":"A person and a dog on a path beside open fields.","status":"Approved","feedback":""}
]
Vlak 0.4.0 reference (a fixed excerpt for every participant):
import { Button, Input, Badge, Dialog, DialogTitle, Textarea } from '@noorddev/vlak-react';
Button: native button props, variant?: 'primary' | 'ghost', size?: 'default' | 'sm'.
Input: native input props, label?: ReactNode, error?: ReactNode, hint?: ReactNode, plain?: boolean.
Badge: native span props, variant?: 'outline' | 'solid' | 'muted'.
Textarea: native textarea props, label?: ReactNode, feedback?: ReactNode.
Dialog: native dialog props except open/onClose, open: boolean, onClose?: () => void, dismissable?: boolean, lightDismiss?: boolean, closeLabel?: string. It uses a native modal dialog; control open in React state. Do not call showModal yourself.
DialogTitle: native heading props, as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'. It supplies the dialog's accessible name.
The installed stylesheet uses --bg (page background), --text (foreground), --text-secondary (muted text), --divider (border), --table-alt (subtle surface), --radius, --gutter, and --rs-gap. Use the actual supplied token names. The package loads its own Inter font. With no data-theme override, system preference applies. Do not force light mode.
Output and factual run report:
Return exactly three fenced blocks in this order, with no other text. The first two must contain complete source. The third is a factual report about this response, not code to execute.
```tsx filename=App.tsx
[complete App.tsx, default-exporting App]
```
```css filename=app.css
[complete stylesheet]
```
```json filename=run-report.json
{
"task_id": "review-room-plan-v2",
"model_name": null,
"model_version": null,
"model_identity_source": "unavailable",
"reasoning_setting": null,
"generation_elapsed_seconds": null,
"timing_source": "unavailable",
"timing_scope": null,
"input_tokens": null,
"output_tokens": null,
"tools_used": [],
"limitations": []
}
```
Report your actual model and version only if they are explicitly exposed by your runtime. Set model_identity_source to "runtime" only in that case. Do not infer your identity from this prompt, previous knowledge, branding, or the task. Use null and "unavailable" when exact identity is not exposed. Report the reasoning setting only if it is exposed, otherwise null.
Report generation_elapsed_seconds only if actual runtime timing or timestamps let you measure from receipt of this request to completion of the final code block. State the timing source and exact scope. Do not estimate duration from token count, reasoning effort, a feeling of elapsed time, or a claimed internal clock. If no measurement is available, use null, timing_source "unavailable", and timing_scope null. Do not call tools to obtain timing; the no-tools rule still applies. This self-report does not replace the operator's Send-to-complete stopwatch.
Report token counts only when actual usage metadata is available, otherwise null. List any tools actually used despite the instruction; use [] if none. Explain missing identity or timing in limitations. Do not claim a build or test was run; source generation alone does not run either. Keep model names, timing, and these notes out of the app UI.
Tools, in order
Here is where each tool helps. Use an equivalent you already work with if it fits the task and your project’s access requirements.
Before comparing
Choose representative design tasks and save the same brief, references, evaluation criteria, and tool permissions for every run.
Carry forward A dated comparison brief.
During trials
Claude, ChatGPT, or GrokA coding workspace with approved file access
Use the same frozen prompt in every app within each task. Time one response, preserve the unedited code, and record tool use, continuations, and unavailable metadata.
Carry forward Versioned outputs with recorded model and setting labels.
After inspection
Browser and accessibility checksNotion
Rate hierarchy, craft, interaction, mobile and keyboard use, and use of Vlak. Keep reported duration and technical checks separate. Record the first change you would make; measure repair time only in a separate revision round.
Carry forward A task-specific preference with supporting evidence.
Review the work with partners
We make and revise the work with Claude, ChatGPT, or Grok, then put selected versions on our Studio project pages for partners to review. Check the preview before sharing it. You can do the same with a private prototype or shared document; use a workspace that can access the files you need.
Name the version, say what changed, and ask the question you need answered. Keep feedback with that version and discuss conflicting requests before making the next changes. Confirm approval separately, and keep confidential work in a restricted space.
A question for this review
Which output serves the work best when model labels are removed, and what evidence supports that choice?
Delegate the routine work
Normalize run metadata and assemble a blinded comparison sheet from existing outputs.
Design quality, task fit, and the final recommendation need human evaluation.
Product documentation
Follow these links for the providers’ current instructions. They describe capabilities, not independent evidence for Noord’s model preferences.