Skip to content

Design and wording ​

The look, the wording, and Anubis's own pages. Part of Experiments and decisions. Newest notes go at the top of each section.

Report a problem (2026-09-30) ​

  • The owner asked for a bug report button people can find easily. Report a problem is in the toolbar popup's footer, beside Help, and in the Settings sidebar's links; the troubleshooting guide starts with it. It opens GitHub's issue form (.github/ISSUE_TEMPLATE/bug-report.yml) with the fields filled in by id from the link: Anubis's version, the browser and system from the user agent ("Firefox 143 on Linux"), and, from the popup on a search page, the engine's name. Nothing from the page goes in (no address, no search), and nothing is sent until the issue is submitted. Not put on search pages: the summary stays quiet, and the popup is one click away. tests/bug-report.test.ts checks the link only names fields the form has.

Tags in the site popup (2026-10-03) ​

  • Found: the toolbar popup let people press a tag for the current site, but the selected state was too subtle to spot. It also had no way to create a tag there, despite both actions being available in the search-result menu.
  • Changed: selected tags now use their own colour for a 2px underline and bold text, without a fill. The popup always shows a compact New tag field, which adds a tag to the personal list and applies it to the current site; an existing shared tag is reused. Empty or duplicate names are explained beside the field. The action keeps keyboard focus on the selected tag after the popup redraws.
  • Checked: a new popup e2e part covers selecting, creating, styling, focus-safe redraws, and narrow viewports; it runs in CI.

Explanations on tagged sites (2026-10-04) ​

  • Added: every tagged site in the bundled FOSS tools list has an inline comment saying why it belongs. The Anubis list parser ignores trailing # comments, so these explanations do not change matching.
  • Added: Settings → Tags accepts an optional reason alongside a site. It is saved as a comment on the personal-list rule and shown under the site in the tag editor.
  • Compatibility: the note stays in the existing plain-text personal list and follows site edits and sync merges; old rules without notes remain unchanged.
  • Layout fix: the shared inline-form input rule also matched the reason nested inside its label, giving the text field a 260px flex basis on the column axis. The tag-note e2e check now asserts that it remains a single-line field.
  • Not used: the tag's definition description; that describes the label for every site, not why one site fits it.

Finishing touches (2026-09-29) ​

  • Second follow-up (2026-09-30): red for a ranking is now a written rule, not only a fix: STYLEGUIDE.md's principles, CLAUDE.md, and CONTRIBUTING.md say --danger is only for errors and deleting, and tests/palette.test.ts fails when a CSS rule for Hide uses it. "Clean up" in Settings read as housekeeping rather than what the page does; it's now Remove panels everywhere people see it (the settings section, the README and wiki features, the guide's title, the homepage, and the store listing), with #cleanup and guide/clean-up kept so links still work. The tag switch lost its "Shown" label, which only repeated what a switch in that place does (its tooltip and label for screen readers stay). Tags describe a result, so the Paywalls list's tag is now "Paywalled" (its id stays paywall, so tag choices carry over), and lists/README.md asks list authors to name tags that way. The name and logo at the top of Settings open the wiki.
  • Follow-ups (2026-09-30): the welcome page's logo read as too small beside the taller header; it's now 112px (72px on phones). The balance no longer swings as the page opens: the owner wanted it to move only when clicked. A chosen Hide was red (--danger) in the popup, the result menu, Settings, and the Introduction's demo, which the owner found out of place in the palette. It's now grey: the text colour with a --muted underline, the same weight as the other rankings. --danger is kept for errors and destructive actions. In Settings → Tags, Edit followed each tag's sentence, so it sat somewhere different on every row. It's now in the row's controls, after Shown, with a fixed-width dropdown so it lines up.
  • Asked for: the project owner wanted the extension to look better, with small, tasteful additions rather than anything loud. Ten were mocked up beside the current build, in both schemes. The mockups aren't in the repository.
  • Shipped: a diamond before the popup's status, gold while Anubis is on and hollow while it's off. A second, fainter hairline inside the cartouche, as carved cartouches are drawn, in the popup and the result menu. Each ranking's icon over its name, muted until it's chosen. In Your sites (the popup and Settings), the ending a site shares with others (.org, .co.uk) is muted, and a site with only a tag shows that tag instead of "1 tag". The popup's empty Your sites list shows the balance, level and empty, in grey. The matched rule under Why is split into its options (utils/ruletext.ts) and breaks only after a comma; before, it wrapped mid-word ("tuto" / "rial"). The welcome page's balance swings and settles level as the page opens, and a click on either side presses that pan down to swing again (the owner asked for it to react to something). It holds still with reduced motion.
  • Rejected: a faint gold glow behind the balance, with a ground line under its foot ("too much"). A grain on extension pages' backgrounds, to make the light scheme look like honed stone ("not needed"). Counts in the summary's sentence set in the text colour at 500, to be read at a glance ("no").
  • Checked: unit tests for splitSuffix and ruleParts, including that the parts join back into the exact rule; the popover e2e part checks that the menu shows the rule as written. The checks, responsive, welcome, a11y, mobile, and options parts pass. The regenerated popup, menu, and Your sites screenshots were rendered in a container whose fonts differ from the other screenshots'; regenerate them with node e2e/run.mjs docs on the usual machine to match.

Patterns from Dark Reader (2026-09-29) ​

  • Reviewed: Dark Reader's dynamic style-position watcher batches and deduplicates DOM work; its content-script lifecycle accounts for page freeze and resume. The useful lesson is to bound repeated work and make lifecycle transitions explicit, not to transplant its stylesheet-specific machinery.
  • Adapted: Anubis already batches mutations to one pass per frame. It now disconnects the observer and cancels any queued frame on pagehide, then observes and schedules a fresh pass on persisted pageshow, so a restored page catches up with changes made while frozen. The checks e2e part simulates that lifecycle and asserts both the pause and rescan.
  • Compared with uBlock Origin: its content-script DOM watcher centralizes mutation subscribers and disconnects when unused. Anubis has one consumer, so a separate watcher service would add indirection today; extract one if more independent DOM features need the same lifecycle. uBlock's listener-error suppression is deliberately not adopted.
  • Deferred: Dark Reader and uBlock Origin Lite's CSS handler show ways to deduplicate and bound mutation work. Incremental per-result passes could reduce work on busy pages, but Anubis also recalculates cleanup, grouping, filtering, reranking, summary placement, and page statistics. Retain the full pass until profiling and a complete invalidation model justify changing it; do not transplant stylesheet-specific or miss-count heuristics.
  • Compared with Vimium's Firefox build: its unit-test helper and browser DOM tests support the same split Anubis uses: fast rule tests, then fixture-backed browser checks. Vimium's build checks also reinforce checking generated browser artifacts; Anubis already checks the built Firefox minimum in CI. Keep permissions narrow rather than borrowing Vimium's broader host access, which serves a different feature set.
  • These projects point to small, testable patterns, not a reason to replace Anubis's plain TypeScript/WXT structure. Browser fixtures still complement, rather than replace, live engine checks.

Settings on narrow screens (2026-09-29) ​

  • Found: at 320px, the Your sites table forced the whole Settings page wider than the screen. The labelled ranking choices in the Add a site form also wrapped as an accidental run of buttons.
  • Rejected: changing the table to display: block stopped the page overflow, but made site names wrap one character at a time and separated the table columns.
  • Shipped: keep the table semantic and scroll it horizontally inside its own wrapper on screens up to 360px; keep its columns together, wrap the labelled ranking choices in a small grid, and put Add on its own line.
  • Checked: every Settings section stays within the viewport at 320px, 360px and 390px in Chromium. At 390px the sites table fits without scrolling; below that only the table can scroll.

Welcome page ​

Asked for: pinning and the starter lists were only explained in the user guide, which people rarely open before their first search.

  • Shipped: entrypoints/welcome/, opened by the background script when runtime.onInstalled says install (never on updates, and it needs no permission). It gives this browser's steps to pin the toolbar button, a search to try on four engines, and the lists you're subscribed to with the tags each adds. The search is "python list comprehension", which brings up official docs, forums, and Wikipedia, so three of the four starter lists show a tag. The lists come from storage rather than the directory, so a reinstall that syncs other subscriptions shows those.
  • Pinned or not: Chromium browsers answer action.getUserSettings() with isOnToolbar, and newer Chrome fires onUserSettingsChanged. The page checks on load, on that event and when the window regains focus, and says "Anubis is in your toolbar." instead of the steps once it is. Where the browser doesn't say, the steps stay. The e2e browser can't pin, so only the unpinned state is tested.
  • Not done: browser_action.default_area: "navbar" for Firefox, which would put the button on the toolbar straight away. Firefox's own default keeps new buttons in the Extensions panel, and the steps cover it.
  • Firefox for Android has no toolbar for extensions; the page still shows Firefox's desktop steps there. Fix that when Android is checked (ROADMAP.md).
  • npm run dev starts with a fresh browser profile, so it opens the welcome tab each time.
  • Too narrow on a desktop (2026-09-29): one 580px column in a wide window read as a phone layout. It now uses the settings page's shape: 1040px, section titles in a 220px column and what to do beside them, the lists two across. Below 900px it's one column again. Checked at 1920, 1180, 820, and 390px.

Translation ​

  • Tried: WXT's @wxt-dev/i18n module. It's typed and reads YAML, but its README says its plural forms don't support languages with separate "few" or "many" forms (Arabic, Polish, Russian…), and it adds three dependencies.
  • Shipped: the browsers' own _locales/<language>/messages.json format, which translation tools read as they are, with a small helper (utils/i18n.ts). Keys are type-checked against the English file. Counts use Intl.PluralRules with keys like popupListCount_one and popupListCount_other, falling back to _other. A langCode message gives the language the text is actually in, for the page's lang attribute, since a missing translation falls back to English.
  • WXT types getMessage with one overload per key, which a key held in a variable can't satisfy, so the helper calls it through a looser signature.
  • The fake browser in unit tests has no i18n; useEnglish() in tests/english.ts answers from the English file.
  • The summary's buttons (2026-09-29) now use the popup's messages (showHidden, loadMore…), so the two can't drift apart: the page's Load more results tooltip had its own wording. The cog's label, shared by the popup, the summary, and the result menu, lost its popup prefix (anubisSettings).
  • The summary sentence (2026-09-29) read "Anubis raised 1 and hid 2 of 7 results, and removed an AI answer, a video panel…": two "and"s in one sentence, the second after a comma, so the clean-up part read as tacked on. What clean-up removed is now a second sentence ("… of 7 results. It also removed an AI answer, a video panel…"); on its own it stays "Anubis removed a question list." The sentence moved into messages on the way: each shape has its own message (summaryActed, summaryAlsoRemoved, summaryRemovedOnly, summaryUnchanged, summaryFiltered), counts use plural forms, and lists are joined by tJoin with Intl.ListFormat. Plain en joins "a, b, and c"; the English text is British, so English lists use en-GB, "a, b and c", as andList did. tests/english.ts answers getMessage from the English file for any test that needs it.
  • The serial comma (2026-09-29) replaced that choice the same day: lists of three or more now take a comma before the last "and" or "or" ("Hide, rank, or tag"), in the interface, the wiki and the repository's own docs. tJoin uses plain Intl.ListFormat for the language again, andList adds the comma, and STYLEGUIDE.md states the rule. Quotations of earlier wording in this file keep their original punctuation.

Wording, icons, and the motif ​

Feedback from use: "weigh" was too ambiguous for the functions people rely on ("Weigh deeper", "Weigh a site", "Weigh this site"), the settings button's icon read as a sun, and the Anubis logo on every result said who made the button, not what it does. The motif (the balance in the menu, the cartouche) was liked; it was the words and icons that got in the way.

  • Inspiration: Scott Jenson's talk "Are we really going to use the same Desktop UX forever?" (KDE Akademy 2026) treats UX as layers (style, structure, strategy, technology) and argues for tools shaped around the task in front of you rather than around the software. Here the style layer (the Egyptian theme) had leaked into the structure layer (the names of functions). The ux-heuristics skill (Krug's Don't Make Me Think, Nielsen's heuristics) was installed in .claude/skills/ for the review. It flags this exact pattern: clever names lose to clear names, and icons without labels make people guess ("mystery meat navigation").
  • Changed: "Weigh deeper" is now "Load more results" (and "Loading…"), and "Look deeper automatically" is "Load more results automatically". "Weigh a site" is "Add a site". The per-site choice is called its ranking everywhere (Hide, Lower, Normal, Raise, Pin). The button on each result shows up and down arrows with the label "Hide, rank or tag this site". The summary's gear is now a text button, "Settings". The fallback summary "Anubis weighed 9 results" is now "Anubis left all 9 results as they were".
  • Later: the Settings buttons (in the summary, the result menu, and the popup) went back to an icon on request, this time a toothed cog (Lucide's "settings" icon) rather than the earlier circle with rays, which read as a sun. A cog is one of the few icons almost everyone recognises; each has a label for screen readers and a tooltip.
  • Kept: the balance and cartouche in the menu, the logo as the summary's mark (it says the line comes from Anubis), and the myth in the README.
  • Considered: a "⋯" button for the result menu. Rejected because Google and DuckDuckGo already put their own "⋮" menu on each result, and two lookalike menus would be confusing.
  • The button on each result (2026-09-29): the up and down arrows only said "move", and the project owner asked for something better. Four Egyptian-themed glyphs were drawn at their real 15px on light and dark mock results: the balance, a balance that tips with the site's ranking, an upright cartouche, and Ma'at's feather. The owner chose the balance, tipping with the ranking but without colour, and asked for a pin on pinned sites and something else for hidden ones. The button now shows the balance level for Normal, the site's (left) pan down for Lower, and up for Raise, as the menu's balance tips; a pinned site shows the ranking's pin and a hidden one its crossed-out eye. Its label adds the ranking ("Hide, rank or tag fandom.com (lowered)"), since the tilt is a state. The cartouche was hard to recognise at that size, and the feather already stands for Normal and can read as "edit". Docs now call it the ⚖ button.
  • Also considered: Vercel's web-design-guidelines skill. Not installed, because it downloads its rules from the network on every run.

Toolbar icon when off ​

  • Turning Anubis off now swaps the toolbar icon for a grey copy (public/icon-off/) and sets its tooltip to "Anubis is off". The grey icons were made once from the colour ones with a canvas in Chromium: luminance, flattened, 75% opacity, so they read as "off" on light and dark toolbars. The icon is set every time the background script starts, because the browser forgets a changed icon on restart.

Design ​

  • First pass (rejected by the project owner as loud and "a bit like Discord"): filled pill badges with coloured dots, gradient gold buttons, and segmented controls, ALL-CAPS section labels, rounded cards everywhere, a bordered summary with stat counters.

  • Second pass, following Anthropic's frontend-design skill (now in .claude/skills/): on search pages Anubis uses the page's own font and muted text; tags are a small diamond and a name; the summary is one sentence; hidden results are one line. The one flourish is the weigh menu: the site's name in a cartouche (the oval that encloses names in hieroglyphs) over a small balance that tilts with the chosen weight. Settings use rows and hairlines; the light theme is a cool stone grey instead of cream; tag colours are muted Egyptian pigments.

  • Consistency pass and a style guide (2026-09-29): STYLEGUIDE.md now writes down the palette, type scale, radii, controls, states, and wording. Differences found and removed on the way: the result menu's light scheme was warm (#fbfaf8 card, #6f695e muted text) while the popup it's meant to match was cool stone, and the dark hairline was #36322b against #35312a, so shadow.css now carries the same tokens under the same names as theme.css (--text, --raised, --line-strong); small print came in 12px and 12.5px, now 12.5px; the popup's sentence was 13.5px, now body size; selects used the browser's arrow everywhere except the cartouche, now all use its small caret; a tag filter's underline was 1.5px against 2px for every other choice; Hide chosen in the popup was underlined in gold, in the menu and settings in red, now red; the menu's new-tag field was 28px with a faint border, now an input like the others; the logo was rounded in CSS on top of its own rounded tile; the settings tab's title was "·"-joined.

  • The cartouche's bar (2026-09-29): the name sat in a gold oval with a short bar 3px off its right end, the tie at the end of a real cartouche. At this size it read as a text cursor, and the project owner asked what it was. Tried touching the oval at full height, and taller than the oval: both still read as a cursor or a stray line. Dropped; the oval alone carries the motif.

  • The cartouche's name was off centre (2026-09-29): a select is as wide as its longest option, so wikipedia.org sat left in a box sized for en.wikipedia.org, with a gap before the caret. The name is now text with the caret after it, and the native select lies unseen over the whole oval (it still opens the browser's own list and works from the keyboard; the oval shows its focus ring through :has(select:focus-visible)). With one choice there's no select at all, where before a disabled one greyed the name. Choosing another part of the site keeps focus on the picker; before, it jumped to Hide. The popover e2e part switches developer.mozilla.org to mozilla.org from the keyboard.

  • The popup changes with the tab (2026-09-29): the popup showed the same four sections everywhere, and gave the most room (and the only gold button) to typing a domain by hand, the rarest thing people open it for. It had a dropdown for the ranking where the result menu has a choice row, three unlabelled theme icons next to the on/off switch, and × to forget a site with no undo. Three layouts were drawn: a list of every site Anubis acted on in the page's results, with the reason (needs the content script to report per-site verdicts); one "Find or add a site" field at the top; and a popup that changes with the tab. The project owner picked the last. On a search page it shows the summary, its buttons, and the tags to show only (the set-filter message the summary already used); on another site, the result menu's cartouche, balance, rankings, hint, and tags, worked out in the popup with evaluate() on the tab's address; elsewhere, Add a site opens by itself, with Hide, Lower, Raise, and Pin as buttons instead of a dropdown and an Add button. The theme moved to Settings only; forgetting a site moved there too, and the footer's list count opens Settings → Lists. The balance moved to utils/balance.ts so both draw the same one. Mockups of the three are not in the repository.

  • Clean up settings read the wrong way round (2026-09-29): the page listed nouns ("AI answers", "Videos") each with a switch, all off, so "AI answers: off" could read as AI answers already turned off. The project owner found it unclear. The list now sits under "Remove from every search" with one line saying on removes and off leaves it, the intro says to turn on what you'd rather not see, and labels that only named a topic say which part of the page goes ("Video panels", "Discussion panels", "Image rows"); "Discussions" also clashed with the Discussions tag. The Google switch's heading is "On Google" and its hint starts with what it does. Not tried: "Remove …" on every label, which repeated the verb seven times.

  • "Share and back up" was too long for the settings sidebar (2026-09-29): it wrapped onto two lines. The sidebar now says Backup, the most common reason to open it, and the page's title names all three things it does: "Back up, import and share". The address stays #share, since the guide and earlier builds link to it.

  • Tagging sites from Settings → Tags (2026-09-29): a tag's row only had its colour, an inline name field, what it does, and Shown, so the only way to tag a site was the ⇅ menu on a search result, and a tag's sites weren't visible anywhere. The project owner asked to add sites to a tag and edit it from there. Each row now has Edit, which opens the tag's name (a labelled field, where before the name was an input that only looked like one on hover), its description for your own tags, your sites with the tag (× untags), a field that tags one or more sites, and up to eight sites from each list that gives the tag. Open tags stay open when the page renders again after a change, and the cursor goes back to the field, so several sites can be added in a row. At phone width a row's controls now wrap under its name; the name was cut to one letter.

  • Saying what a tag does (2026-09-29): a tag's row read "Most articles need a subscription. From Paywalls, on 23 sites.", which said what the tag means but not what it does; the project owner took Paywall to lower sites, when the Paywalls list only labels them. Each row now opens with a sentence worked out from the tag's setting and, on "Follow the lists", from the lists' own rules: "Marks 23 sites from Paywalls. Only a label: their ranking stays the same.", "Marks 60 sites from Official docs. Official docs raises 51 of them." The tag's description follows in small print. Paywall's description now says which sites it marks. Tag names were left short, since they're also the labels under results.

  • Plain colours on search pages (2026-09-29): the project owner asked for a way to make what Anubis adds to search pages plainer in colour. Settings → Appearance → Colours on search pages now has Gold (the default) and Plain. Plain swaps the tokens rather than each rule: gold becomes the muted grey or the text colour, red becomes grey, tag marks turn grey, and the pinned frame and highlights take the page's text colour. Tags stay distinguishable by name, and what you can press keeps its weight. Settings and the popup stay gold, since the request was about search pages. Not tried: separate switches for tags and gold, which would give two settings for one wish.

  • Style guide redone with examples (2026-09-29): screenshots from the user guide, h() snippets for each control, a table of wording to use and avoid, and the summary as its own section. Checking the code against it found two classes that did nothing: .btn.ghost (Disconnect in Sync) and .danger on a .btn (Reset settings) had no CSS. Disconnect is now a plain button, and .btn.danger exists: red text, a red border on hover. The focus ring had 3px corners on search pages and square ones on extension pages; both are 3px now. Keyboard and screen reader guidance moved out to ACCESSIBILITY.md, which the guide links.

Released under the GNU AGPL v3.