johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
name: ui
description: Build or change knotless's web pages (web/) so they look right, not only work. Use for any change to a page, component or style under web/. Look at every state of what you touch with just look before pushing, hold it to the house rules here, and have it critiqued by eyes that did not write it.
Building knotless's pages
The shots check says what moved; it does not say whether what moved is good, and it only ever draws the states the recorded world happens to hold. A page nobody looked at shows it: a filter that empties a list leaves a bare sentence about the wrong thing, jammed against the controls above it. So look, at every state, before pushing.
AGENTS.md has the mechanics (tokens, component layers, popovers, inline text). This is how the pages should read, and how to check they do.
Looking
just look draws pages as this checkout does, from
harness/shots/fixtures.json, with no PDS, and writes pictures to
target/look for you to open with Read. It builds web/ first; run
node harness/shots/look.mjs ... to skip the build when it is fresh.
just look pull-open # a page by name, desktop light + phone dark
just look '/alice.test/tally/issues?state=closed' # any path
just look / --signed-in # as alice.test, logged in
just look / --set 'getFeed.events=[]' # what a method answers, changed
just look issues --set 'listItems.items.0.title="A title long enough to wrap twice over on a phone and then some"'
just look repository --signed-in --click 'header details.popover summary'
just look pull --element .merge-box --all # one element, in all four
just look check --as bob.test --click 'details.rerun-menu>summary' # as another account
just look / --set 'getFeed.events=@feed.json' # an answer from a file: every kind of line at once
just look / --set 'getViewer.login=true' --click 'header [popovertarget=login]' --type '#login-handle=chadtm' # typed into, then shot
just look org-members --as bob.test --click '.org-invitation .btn.primary' --hold setOrgMembership # a write left under way: its button busy
just look issue --phone --dark --webkit # in WebKit, as Safari and every iPhone browser draw it
--webkit draws in Playwright's WebKit rather than Chromium, for a
layout that wraps or overflows only on an iPhone; its pictures end
-webkit. That WebKit is Linux's, not iOS's: it paints no custom
highlights (code is drawn uncoloured), so a highlighting bug seen on an
iPhone can't be seen in it.
It says when a page is wider than the screen, naming the element that
runs past the edge: fix that before anything else, as the page then
scrolls sideways on a phone. With --click it centres what it clicks and shoots
the screen, not the whole page, as a menu is seen.
Quote --set's argument: the shell takes [] for a glob. An answer
--set changed is held to its method's lexicon, as the server's are,
and one that is not as it says fails the run, naming what is wrong: a
page is only judged on an answer the server could give. The tool
names the methods each page asked for; a --set of any other changes
nothing, and it says so and exits 1. A path that was not recorded is
answered from the same method's answer for another path, which it also
says. A page new to the world needs it in harness/shots/world.mjs and
just shots-record; until then, --set can fill in its answers.
Without a checkout
In a chat with only the knotless MCP, the runner looks instead, at a
branch: commit the change to it, then ask for the look workflow there
with LOOK as just look's arguments, quoted as a shell would, and
read its pictures back.
rerun repo: chadtmiller.com/knotless, ref: refs/heads/<branch>, workflow: look,
env: {LOOK: "profile --phone --set 'getProfile.links=[{\"url\":\"https://example.com\"}]'"}
checks repo: chadtmiller.com/knotless, ref: refs/heads/<branch>, workflow: look,
wait: 60, log: true, images: true
It installs and builds the branch's web/ first, so a look takes about
two minutes: ask knotless run list again, waiting 60 seconds at a time, as a
longer wait can outlast the MCP call itself.
The pictures come back 12 at most: ask for that many. What look says,
a page wider than the screen or a --set that changed nothing, is at
the end of the log. Answers go inline in --set; one too long for that
can be committed as a file and given as @path, and taken out before
the pull lands. A page whose query is new has no recorded answers:
give them with --set until just shots-record records them.
The states to look at
For every list, page or component you touch, each that applies:
- Full, as recorded, and many: rows that wrap, a long run.
- Empty, and empty under each filter, tab or chip it has.
- One, where a plural or a rollup could read wrong.
- Long text: a long handle, repository name, title, branch, label.
- Signed out and signed in (
--signed-in), owner and not. - Phone and dark: the defaults draw desktop light and phone dark.
- Busy: each button that writes, pressed and its write held
(
--hold <method>): the spinner and its words in place, the rest dimmed. - Open: every menu, popover and dialog it has (
--click), on a phone as well. There a menu with much in it (a list to search, a form) is a sheet over the dimmed page; a few actions drop down under their button. Judge where it opens against what was tapped, not only that it fits. - Every kind of row a list draws, when its rows differ by kind (the
feed's pushes, rollups, stars, comments): one
--set ...=@file.jsonanswer holding each, with long names, on a phone.
Look at a sibling page beside yours (below), so the new one matches it rather than inventing.
House rules
Case. Sentence case everywhere: tabs, chips, buttons, menu items,
links in the header and menus, headings, column heads, field labels,
dialog titles, as much as notes and errors ("New issue", "Getting
started", "Log out", "Blocked accounts"). Only the first word and proper
nouns take a capital: days and months, Atmosphere, Bluesky, PDS, DID.
Labels end with no full stop; what is said, a sentence, ends with one.
Names stay as they are written: knotless, handles, repositories,
branches, files, commands, labels such as kind/bug. No
text-transform to change case: write the label as it should read.
Empty states. Say what is empty, in the terms the reader chose: with
Issues picked, "No issues yet" or "No issues in the last N events", not
the page's general blurb. Offer the way out when there is one (all
kinds, everyone's, a clear filter). A list's empty state goes where its
rows would, as .empty does in ItemList's box, not as loose text.
Space. Every block stacked on another has a gap from the space scale between them; text never touches a row of controls. Things that belong together sit closer than things that do not: a heading to its list, less than the list to the next section.
Consistency. A thing done on two pages is done the same way on
both: the same component where one exists (look in web/src/lib before
making one), the same words for the same act, the same order of
controls. Counts, times, people and repositories are drawn by their
atoms and molecules, never by hand.
Icons. Where people go and act: tabs, menu items, header controls,
and buttons such as Fork and Star, each with its Octicon from
lib/icons.ts, the same icon for the same thing on every page (a pull is
pull wherever it is). Not in sentences, nor on every row of a list:
there, the avatar or state mark is enough. An icon shown without its
word still says it, by aria-label or a hidden label. Tabs keep their
words beside their icons on a phone too, and a row too long scrolls.
Weight. One primary button on a view at most. Quiet what is said
about a thing (--mute, --text-sm) next to the thing itself.
Pages to match
- A list with filters:
issues,pulls(ItemList in its box, the search and filter menus above). - One item with its discussion:
issue,pull. - A repository's pages:
repository,commits,file, under RepoPage's header and tabs. - An account:
profile,profile-repos,profile-activity. - Settings: the
settingsroutes under SettingsPage.
Critique
You read your own pictures kindly. Before pushing a change that moves a
page, hand the pictures to an agent that did not write it: the Agent
tool, a fresh one, given the paths under target/look (and a sibling
page's), this file's House rules, and only this question: "What looks
wrong, out of place, or unlike its siblings here? Be specific: element,
what is wrong, which rule." Not the code, nor what you meant: it judges
what is drawn. Fix what it finds, or say in the pull why not.
Then
Push, and the pull's shots check draws what moved against main. Name
the pages you meant to move on its Shots-moved: line; any other that
moved is a mistake to fix.
A state the check does not draw (a menu open, an edit box, a list
emptied by a filter) it cannot show the reviewer: give the pull your
just look pictures of it, each as an --image to knotless pull create or
knotless pull edit, as AGENTS.md says.