Evaluating and Iterating on the Interface¶
How to judge a rendered annotation page and what to change. It ships with the potato-tasks skill:
/plugin marketplace add davidjurgens/potato-skill
/plugin install potato-tasks@potato
A config that validates tells you the server will start. It tells you nothing about whether a person can do the work. That question only has one answer: render the page, look at it, and change something.
The loop¶
potato preview config.yaml --screenshot shot-01.png
Before you start: the PNG is 1280x900 of the top of one page, not the whole
page. Half the checklist below is about things further down. Get a full-height
render by driving a browser against a running server (running-a-task.md), and
treat --screenshot as the fast smoke test rather than the visual check.
Then, in order:
- Read the error lines first. Uncaught exceptions and
console.errormean part of the interface never initialized. Nothing else you notice matters until those are gone — except the three Potato logs on every phase page (/api/current_instance404 and two[SpanManager]lines), which are present on a healthy task. - Look at the PNG. Not the exit code. A clean exit means nothing threw.
- Make one change.
- Re-render to a new filename —
shot-02.png, not the same name. You need the pair to see what your change did.
Keep going until the checklist below passes. Three or four rounds is normal for anything with a custom layout.
What to look for¶
Work down the list. Each line is a failure that has shipped in a real task.
The item
- Is it there at all? A raw file path where an image should be means no
instance_display. - Is it readable — not clipped, not scrolled off, not one line of a long document with no way to see the rest?
- If it is media: does the player have controls, and are they inside the frame?
The questions
- Is every scheme present? Count them against the config. A missing one is
usually behind
display_logic(see below) or failed to generate. - Is any of them empty — a heading with no inputs under it?
- Are the labels readable, or truncated with an ellipsis?
- Do radio buttons and checkboxes actually appear? An invisible input control is the classic CSS collision, and the label text still renders, so the question looks fine at a glance.
- Do tick marks, scale points and their labels line up, or do the labels overlap each other at the ends?
- For a grid or matrix scheme: does it use the full width, or is it squeezed into a narrow column with horizontal scroll?
The page
- Is anything shifted right, overlapping, or overflowing its container?
- Is the Next button visible without scrolling past the fold? An annotator hits it several hundred times.
- Does the whole page scroll horizontally? It should not.
The work itself
- Count the interactions to complete one item: clicks, scrolls, keystrokes. Multiply by the number of items. That number is the study's cost.
- Do the schemes have keyboard shortcuts where they could?
- Is anything ordered so that the annotator has to scroll up and back down?
The states a screenshot will not show you¶
The render captures the page as it loads. Four things live outside that, and each has to be checked another way.
Conditional schemes. Anything behind display_logic is absent from the
initial render, and its absence proves nothing. Comment out the display_logic
block, render, look, put it back. Do this every time — the widget behind the
condition is often the whole point of the task.
Anything that appears after an interaction. A span highlight, a drawn box, a playing video, an expanded section, minting a code, saving a note. Render to confirm the control is there, then drive it if you have a browser tool.
Without one there is still more evidence than the PNG. Run the server once in the background and read what it did:
- the startup log says which subsystems initialized and what they loaded — codebook labels, detected cases, how many instances got indexed
project.sqlitein the task directory holds the codebook, cases, memos and the search index, and can be queried directlyannotation_output/<user>/user_state.jsonshows what a scripted pass actually stored
That distinguishes "the feature is configured and initialized" from "the button is on the page", which is most of the distance. Say in your handover which of the two you established.
Other phases. --phase consent, --phase instructions, --phase training,
--phase poststudy. Only those four plus annotation: the preview CLI refuses
prestudy even though the server supports it as a phase.
A phase-page render exits 1 on a healthy task. Phase pages have no instance,
so the span layer's /api/current_instance 404 and two [SpanManager] console
errors are always reported, and --screenshot counts them. Judge the PNG and the
error list, not $?. See phases-and-pages.md. Each is a page an annotator sees, and the training phase
renders real schemes, so it can break in ways the annotation page does not.
Only render a phase the task actually has. --phase X parks an annotator in
that phase, so if the task never configures one, every route redirects toward a
page that does not exist and the render fails with a redirect loop.
annotation_instructions is the banner on the annotation page, not an
instructions phase — a task can have the banner and no phase.
State across navigation. Answers are saved and restored on a full page reload. If you have a browser tool, annotate, click Next, click Previous, and check the answer is still shown — visually, not just in a hidden input. Do not test this with a page refresh: browsers restore form state across refresh on their own, so a refresh-based check passes even when the server never stored anything.
Changing the interface¶
Reach for these in order. Stop at the first one that fixes it.
| Want | Use |
|---|---|
| Fields side by side rather than stacked | instance_display.layout.direction: horizontal |
| More or less space between fields | instance_display.layout.gap |
| Choices in a row rather than a column | layout on the scheme |
| Shortcut hints along one line | horizontal_key_bindings: true |
| Standing instructions at the top | annotation_instructions |
| Something above every item | header_file |
| A logo | header_logo |
| Colours, spacing, fonts | base_css |
| More room — no navbar, no jump control | hide_navbar, jumping_to_id_disabled |
| An arrangement none of the above reaches | task_layout |
task_layout is last for a reason: hand-written form HTML stops tracking
changes to the schema generators, so a scheme that gains a feature later will
not gain it here. Most requests that sound like they need it are
instance_display.layout plus scheme order.
With base_css, change what you meant to change. A rule that targets a bare
element selector will reach the navbar and the admin pages too.
Iterating without going in circles¶
One change per render. Two changes and a difference you cannot attribute is how a session turns into twenty screenshots and no conclusions.
Keep the screenshots numbered. They are the record of what you tried.
Write down what you were fixing. "shot-03: moved confidence above the span so the page stops reflowing" beats three unlabelled PNGs.
Know when to stop. The interface is done when: no console errors, every scheme visible and usable, nothing overlapping or clipped, the Next button reachable without scrolling, and shortcuts on anything that can take them. Past that you are decorating, and the researcher has opinions you do not have access to. Hand it over and say what you would change next.
Running the task writes to the project directory. The first server start
creates project.sqlite and seeds it — for a codebook task, the labels in your
config become the project codebook. Change the labels afterwards and the
codebook still holds the old ones until potato codebook config.yaml re-syncs.
Worth knowing before you verify a config you are still editing.
When a change does nothing, suspect the key before the CSS. Unrecognized
config keys only warn, so a typo is silently ignored and the feature you thought
you enabled is off. Run potato validate --strict.
Reporting what you saw¶
A handover that says "renders correctly" is not evidence. Say what you checked:
Rendered at 1280×900. Three schemes present, one behind
display_logic(verified separately by disabling the condition — screenshotshot-04.png). No console errors. Keyboard shortcuts on the yes/no question. The consent and instructions phases render (shot-05,shot-06).Not checked: span highlighting behaviour after a drag, and whether answers survive navigating away and back — neither is visible in a static render.
The second paragraph is the part that makes the first one worth reading.