Auric Artisan Browser Extension Developer Reference
Overview
Source-level reference for maintaining the Auric Artisan browser extension, version 1.0.2. It maps how
one source tree under extension/ becomes generated manifests for Chromium and Firefox, the
three runtimes and the messages between them, the settings and storage keys, the accessibility engine,
translation, and the build, test and release commands that keep it shippable.
1. Runtime overview
+
The extension is one source tree that builds four apps for two browser engines. Only the suite,
named Auric Artisan, is published; color, a11y and
devtools set published: false and stay as internal build targets. There
is no bundler and no transpiler: the source is the shipped JavaScript, and the build copies files,
writes manifests and checks the result.
At run time there are three pieces. The background worker owns the browser's own right-click
items, keyboard commands, the badge and privileged relays. One extension page,
popup.html, holds every tool and is shown as the toolbar popup, the Chromium side
panel, the Firefox sidebar or a separate window. The content script owns everything drawn on a web
page. Nothing depends on a server; the only outbound traffic is a page the user chooses to open.
| Layer | Primary responsibility |
|---|---|
packages/runtime/background.js |
Service worker on Chromium, event page on Firefox: browser right-click items, commands, install page, badge, relays for the in-page menu, side panel tracking. |
packages/popup/popup.html and popup.js |
Every tool, the search, Settings, the tour; one page for every surface. |
packages/runtime/content.js |
Declared on every page; vision filters, the inspector, the contrast scan, and lazy imports of the pickers, the right-click menu, the audit overlay and the a11y engine. |
packages/runtime/page-overlay.js |
The audit overlay: boxes, numbered pins, the finding card and the page dock, in a shadow root. |
packages/a11y/engine.js |
The 80-rule WCAG 2.2 engine, imported into the page when an audit runs. |
The version is 1.0.2 for every app. Section 15 notes which parts of the current source the changelog still lists as Unreleased.
2. Source layout
+extension/version.json: the one version every manifest reads.extension/apps/<id>/app.config.mjs:id,name,shortName,brand,geckoId,description(132 characters at most),tabs,defaultTab,features.a11yEngine,publishedandcommands.extension/build/build.mjs: the CLI that copies, composes, localizes, validates and zips.extension/build/compose.mjs:buildManifest(),manifestMessages(),buildMessages()andfilterPopup().extension/shared/fonts/: Manrope and Fraunces.extension/store/: listing copy, artwork and permission justifications.extension/docs/: the extension's own documentation and decision records.extension/dist/<target>/<app>/: build output, git-ignored, plusauric-<app>-<target>-<version>.zipwhen zipping.
| Package | Contents |
|---|---|
packages/popup |
popup.html, popup.js, theme.css,
shell.css, tools.css, app-scope.js,
finding-bridge.js |
packages/runtime |
background.js, content.js, page-overlay.js,
color-picker.js/.css, pickers.js,
date-core.js, context-menu.js, overlay-host.js,
overlay.css, qr.js |
packages/ui |
combo.js/.css, the popup's dropdown |
packages/core |
dom.js, events.js, utils.js, and
finding.js (one finding model for audit, contrast and inspector
results) |
packages/i18n |
boot.js, i18n.js, rules.js,
overlay.js, locales/hi.json,
locales/patterns.hi.json |
packages/a11y |
engine.js, rules/*.js, accname.js,
contrast.js, dom-utils.js, store.js,
analysis*.js |
packages/data |
wcag22.js, aria12.js, html-aam.js,
autocomplete.js |
packages/brand |
marks.mjs, icons/<brand>/; legacy-icons/ is
never shipped |
| App | Name | Tools |
|---|---|---|
suite |
Auric Artisan (published) | All 18, default pick |
color |
Auric Color | 12: the eight Colour-space tools, contrast, history, library
and launch; default pick |
a11y |
Auric Accessibility | scan, contrast, vision, inspect,
history, launch; default scan |
devtools |
Auric Developer | inspect, tokens, snippets, pick,
convert, contrast, library,
launch; default inspect |
The build copies flat: packages/popup, ui and runtime land
at the bundle root; core/, i18n/, fonts/ and the brand's
icons/ land in folders of those names; a11y/ and data/ are
added only when features.a11yEngine is set (the suite and the a11y app).
3. Manifest generation and permissions
+
There is no manifest in the source tree. buildManifest(app, { version, target }) in
compose.mjs writes extension/dist/<target>/<app>/manifest.json
from MANIFEST_BASE and the app config. The manifest's description, action title,
sidebar title and command descriptions are __MSG_…__ placeholders resolved from
generated _locales/en and _locales/hi, with
default_locale: "en".
| Field | Chromium (chrome) |
Firefox (firefox) |
|---|---|---|
| Background | service_worker: "background.js" |
scripts: ["background.js"] (event page) |
| Workspace | side_panel.default_path: "popup.html" |
sidebar_action.default_panel: "popup.html" |
| Permissions | activeTab, scripting, storage,
clipboardWrite, contextMenus, sidePanel |
The same without sidePanel |
| Optional permissions | clipboardRead, downloads, sessions,
requested at run time when the custom right-click menu is turned on |
|
| Host access | <all_urls> |
|
| Content scripts | content.js only, on <all_urls> at
document_idle, all_frames: false |
|
| Web-accessible resources | The runtime modules and CSS, the i18n engine and dictionaries, the two
fonts and core/*.js, plus a11y/*.js,
a11y/rules/*.js and data/*.js in builds with the engine. No
use_dynamic_url: with it, the content script's import()
calls fail on every site. |
|
| Gecko settings | Not used | id from geckoId (the suite:
[email protected]), strict_min_version: "115.0",
data_collection_permissions: { required: ["none"] } |
| Suite command | Default key | Handled as |
|---|---|---|
_execute_action |
Alt+Shift+A |
Opens the popup |
open-contrast |
Alt+Shift+C |
Queued popup route to contrast |
extract-palette |
Alt+Shift+E |
Queued route to palette, clicking aa-extract-btn |
toggle-vision |
Alt+Shift+V |
aa-vision-toggle (deuteranopia) to the page |
inspect-element |
None | aa-inspect-start to the page |
run-a11y-audit |
None | Queued route to scan, clicking aa-scan-run |
The focused apps carry their own commands: the a11y app binds run-a11y-audit to
Alt+Shift+R, and the devtools app binds inspect-element to
Alt+Shift+I and adds extract-tokens without a key. The build fails on a
description over 132 characters (the source or any translation), a key claimed twice, a Firefox
manifest without data_collection_permissions, a referenced file missing from the
bundle, an absolute path in popup.html, a declared tab with no panel, or a default
tab that is not declared. Permission changes are user-visible in the stores and belong in the
changelog.
4. Popup shell, surfaces and spaces
+- Surfaces.
popup.jssetshtml[data-surface]before first paint:panelwhen the URL has?surface=panel, otherwisepopup.background.jspoints the side panel (sidePanel.setOptions) or sidebar (sidebarAction.setPanel) atpopup.html?surface=panel, and the window button opens the same URL withwindows.createas a 620 × 700 popup window. - Tab registry. A hidden
nav.aa-tabsholds onebutton.aa-tab[data-tab]per tool, and each tool is a<section class="aa-panel" data-panel="…">.filterPopup()removes the buttons of tools an app does not ship, marks their panelsdata-app-excluded="true"(the markup stays becausepopup.jsbinds listeners to it at load), activates the default tab and writesdata-app,data-tabsanddata-default-tabon<body>.app-scope.jsstops a restored tab from showing an excluded tool. Keepclassbeforedata-panelon each section; the filter's pattern depends on that order. - Spaces.
SPACESlists Home plus four spaces;TOOL_METAgives each tool its label and icon. A space whose tools are all excluded from a build is hidden. - Side panel layout.
adoptPanelLayout()moves the theme and Settings buttons into the rail and opens a port namedaa-panelto the background, posting its window id. - Home.
renderDashboard()drawsHOME_ACTIONS.popup(Pick a colour, Contrast, Inspect, Audit this page) as a launcher in the popup, andHOME_ACTIONS.panel(Pick, Inspect, Audit, Vision) inside the tab card on the panel surface, with the colour of the day, the page's colors, recent colors, Continue, pinned tools and site links. - Scripts.
i18n/boot.jsruns in the head; then the classic scriptspopup.js,app-scope.jsandcombo.js, then the modulescolor-picker.jsandfinding-bridge.js, which publishwindow.AAColorPickerandwindow.AAFindingfor the classic code. - Styles.
theme.cssis the only token deck (--aa-*, per theme onhtml[data-aa-theme]);shell.csscovers the chrome,tools.cssthe tool panels,combo.cssthe dropdown andcolor-picker.cssthe picker.
| Space | tools |
deep (opened from another tool or search) |
|---|---|---|
colour |
pick, palette, image, gradient,
blender |
harmony, shades, convert |
check |
contrast, vision, scan, findings |
— |
code |
inspect, tokens, snippets |
— |
saved |
library, history |
launch |
5. Search and settings
+
Search is backed by COMMANDS in popup.js: 29 entries of type
panel, launch (an auricartisan.com route) or click (a
header button). commandIsAvailable() hides panel commands whose tab the build
removed, and onPage: true flags tools that need a web page.
SETTINGS_INDEX adds 15 settings, each with settingTab and
settingControl so a result opens Settings at the control. Every typed word must match
the title, description, group or keywords, in English or translated; an exact title ranks first.
Add a COMMANDS entry, a SPACES slot and a TOOL_META label
with every new tool.
Settings live in one object under aa_settings, initialized from
DEFAULT_SETTINGS. On load, stored values are merged over the defaults and
pickers is merged key by key, so a new picker type starts on. content.js
keeps its own copy of the defaults it needs.
| Key | Default | Effect |
|---|---|---|
themeMode | 'dark' | system,
light or dark |
accentColor | '#d3af37' | The accent tokens, in the popup and in page overlays |
uiSize | 'normal' | compact,
normal or large popup size |
lang | 'en' | en or
hi |
copyFormat | 'hex' | hex,
rgb, hsl or oklch |
naming | 'css' | css,
xkcd or off |
history, apca, context | true |
Keep history; show APCA; items in the browser's right-click menu |
sound | false | A beep on pick or copy |
customPickers | false | Master switch for the website pickers |
pickers | all true | Per type:
color, select, date, time,
datetime, month, week, number,
range, multiselect, datalist, file,
checkbox, radio |
pickersRespectSite | true | Leave designed controls alone |
pickerExcludeHosts, cmExcludeHosts | [] |
Never-on sites for pickers and for the custom menu |
customContextMenu | false | The in-page right-click menu |
cmStepAside | true | Yield to a site's own right-click menu |
scanDeep | true | Contrast-scan limits: 3,500 elements and 160 issues, or 1,800 and 80 |
scanAutoOutline | false | Outline findings right after an audit |
replaceNativePickers, pickersUnified | false |
Legacy color-input switch and a one-time migration marker |
onboarded | false | Set when the first-run tour closes |
Imported settings pass through sanitizeImportedSettings(): enums must be known
values, booleans must be booleans, accentColor must be a 6-digit hex, only known
picker keys survive, and host lists are cleaned, de-duplicated and capped at 100. A new setting
needs a default, a control, an importer rule and a SETTINGS_INDEX entry.
6. Storage contract
+| Key | Store | Shape and limits |
|---|---|---|
aa_settings | storage.local | The settings object above. |
aa_history | storage.local | Picked hex colors,
newest first, capped by HISTORY_MAX = 50. |
aa_lib_colors | storage.local | Library colors,
up to LIB_COLORS_MAX = 500; the badge counts them. |
aa_lib_palettes | storage.local | {id,
colors[], label?}; saves keep the newest 30, a restored backup up to 100 palettes of
up to 64 colors. |
aa_snippets | storage.local | {id, type,
title, code, url, host, ts}; 200 snippets, code up to 20,000 characters. |
aa_pinned_tools | storage.local | Command ids
pinned on Home, up to 8; default pick-color, palette,
contrast, shades. |
aa_last_tool | storage.local | {panel,
ts} for Home's Continue. |
lastPick | storage.local | The last picked hex. |
aa_cm_prefs | storage.local | {quick,
labels, layout, density} for the custom menu; the quick bar holds 6. Kept apart from
aa_settings so menu writes do not rebuild every tab's menu. |
aa_pending_command | storage.local | {panel,
action, createdAt} written by the background; read once, ignored after 30 s. |
aa_last_inspect | storage.local | The pinned
inspector snapshot (schemaVersion: 2), bounded to 512 KB. |
aa_lang, aa-space-tools, auric-cp-* |
Extension-page localStorage | The language mirror read at boot, the last tool per space, and the color picker's recent colors and layout choices. |
Nothing is synced and nothing injected into a website reads or writes that site's storage. Audit
results live only in popup memory. a11y/store.js defines an IndexedDB database
(auric-a11y) for scan history and ships in engine builds, but no runtime code imports
it, so no database is created. Backups (kind: "aa-backup",
schema: 1) carry settings, history, library colors, palettes and snippets. Prefer
additive schema changes and update the importer with every shape change.
7. Background worker
+
background.js normalizes browser and chrome, and keeps its
logic small and event-driven; page analysis runs in the content script.
runtime.onInstalledopenshttps://auricartisan.com/?utm_source=extension&utm_medium=installon first install, then builds the browser menu, refreshes the badge and flags the panel surface.onStartuprepeats the last three.- The
MENUitemsaa-inspect,aa-extract,aa-scan, fouraa-vision-*simulations andaa-vision-clearare built on thepageandactioncontexts whilesettings.context !== false, with Hindi titles from the bundled dictionary whenlangishi. sendContentMessage(tabId, message)triestabs.sendMessage, then injectsoverlay.cssandcontent.jswithscriptingand retries once, which covers tabs opened before the install.queuePopupAction(panel, action)writesaa_pending_commandand callsaction.openPopup(); the popup opens that panel and clicks the button whose id isaction.- Relays for the in-page menu:
aa-perms,aa-download,aa-view-source,aa-open-window,aa-new-tab,aa-reload-bypass,aa-capture,aa-tab(reopen,duplicate,pin-toggle,mute-toggle,close) andaa-zoom(0.25–5). URLs passsafeUrl(), which allows onlyhttp:,https:,data:andblob:. - Side panel tracking: panel pages hold an
aa-panelport and post their window id;aa-panel-openanswers whether the sender's window has one, andaa-open-panelopens the panel (or Firefox sidebar) inside the click's user gesture and queues the requested tool. aa-set-contextbuilds or clears the browser menu;storage.onChangedonaa_settingsrebuilds it too.refreshBadge()shows the Library color count on#d3af37, as99+above 99.
8. Content script and message protocol
+
content.js runs in the isolated world, guarded by
window.__auricArtisanLoaded so a second injection does nothing. It merges
aa_settings over its defaults and, on load and on every change, applies the theme,
the language, the color picker, the website pickers and the right-click menu in that order.
Heavy modules are imported with import(runtime.getURL(…)) only when needed:
color-picker.js for color-input replacement, pickers.js when customPickers is on and
the host is not excluded, context-menu.js when customContextMenu is on,
page-overlay.js for audit outlines, a11y/engine.js on
aa-scan-page, and the i18n engine for Hindi.
| Message to the page | Payload | Effect and reply |
|---|---|---|
aa-vision | filter or null,
strength 0–1 | Apply or clear a filter; {ok} |
aa-vision-toggle | filter? | Clear if active,
else apply (default deuteranopia); {ok, active} |
aa-vision-side | filter | Toggle the
side-by-side comparison; {ok} |
aa-scan-outline | {options} or
{clear: true} | Draw the audit overlay from a contrast scan (the
list's options, so pins and rows number alike), or close it; {ok, scan} |
aa-audit-select | index | Select a pin and open
its card; {ok} |
aa-scan-page | options: {limit, issueLimit} |
Contrast scan plus the full audit; {ok, scan, a11y}, with
a11y: null in builds without the engine |
aa-inspect-start | sourceTabId,
inspectSessionId, pageUrl | Start inspecting;
{ok, sourceTabId, inspectSessionId} |
aa-inspect-stop | session | Stop and undo previews;
{ok, restored, snapshot} |
aa-inspect-highlight | selector + session |
Pin an element; {ok, snapshot} |
aa-inspect-navigate | direction + session |
parent, child, previous or
next; {ok, snapshot} |
aa-inspect-apply-css, aa-inspect-reset-css |
selector, cssText + session | Apply or undo a reversible inline-style preview |
aa-picker-replacement | enabled | Turn color-input replacement on or off |
Every aa-inspect-* message except aa-inspect-start must carry the
session that started the inspector, or it is refused, so a stale popup cannot drive a page it no
longer describes. The page reports back to the popup and panel with
runtime.sendMessage: aa-audit-selected (index) when a pin
is selected on the page, and aa-audit-closed when the overlay closes. The inspector
asks the background aa-panel-open when it starts, and keeps a compact card on the
page when the panel will show the details.
9. Color engine and contrast math
+- Popup math.
popup.jsholds the conversions (sRGB and linear, HSL, HSV, CMYK, LAB, LCH, OKLAB, OKLCH, HWB), the CSS named-color map, WCAG ratios and APCA Lc. Keep these helpers deterministic and side-effect free; Contrast, Page palette, Harmony, Scale, Gradient, Mix and Convert all reuse them. - The Picker.
runtime/color-picker.jsis the website'sjs/components/color-picker.jsplus extension-only safety. ItsFORMATSare HEX, RGB, HSL, HSV, HWB, CMYK, LAB, LCH, OKLAB, OKLCH, XYZ and P3, and its sections are Specs, Harmony, Scale, Contrast, Vision, Code, Page and Recent. - WCAG rows. AA Body 4.5, AA Large 3, AAA Body 7, AAA Large 4.5, AA UI 3 and Gfx 3. APCA tiers are Lc 90, 75, 60, 45 and 30.
- Fixes. Targets are AA 4.5:1, AA Large 3:1, AAA 7:1, APCA Lc 60 and APCA Lc
75.
huePreservingFixes()walks lightness out from the base color, keeping hue and saturation, and returns up to six passing candidates for text and for background. - Contrast scan.
runContrastScan()incontent.jscomposites backgrounds up the tree. Text is large at 24 px or more, or 18.66 px bold; the threshold is 3:1 for large text and 4.5:1 otherwise. A pair within 1.5 of its threshold, or over a background image or text shadow, is a warning or manual review. - Page palette.
extractPaletteInPage()runs in the tab throughscripting.executeScript: up to 6,000 elements, 12 color properties, custom properties weighted three times, the top 48 kept;clusterPalette()merges near-duplicates and the Dominant mode clusters to eight. - Gradients.
interpolatedStops()writes 13 stops for the OKLCH and HSL options; the OKLCH option mixes in OKLab.
When changing color math, check every tool that copies, exports or stores color data: one helper feeds previews, accessibility results and saved library payloads at the same time.
10. Accessibility engine and audit overlay
+| Fact | Value |
|---|---|
| Source | packages/a11y/ with the standards data in
packages/data/ |
| Rules | 80 in 8 categories (aria 17, names 5, structure 12, forms 10, media 13, keyboard 8, contrast 4, document 11): 59 per element, 21 page-level |
| Levels | 69 at A, 9 at AA, 2 at AAA; the audit runs at level AA, so 78 rules run |
Options passed by content.js | level: 'AA',
timeoutMs: 30000, maxElementsPerRule: 25000,
maxIssuesPerRule: 250; the engine yields every 12 ms
(sliceMs) |
| Shipped in | Builds with features.a11yEngine: the suite and the a11y
app |
| Exports | audit(), auditStream(),
serializeReport(), DEFAULTS, ELEMENT_RULES,
PAGE_RULES |
- Every rule skips the extension's own UI (
OWN_UI_SELECTORina11y/dom-utils.js: the vision overlays, the color picker and[data-aa-overlay]). A rule that throws is recorded inruleErrorsand the audit carries on. - The engine's limits are separate from
scanDeep, which sets the fast contrast scan'slimitandissueLimit(3,500 and 160, or 1,800 and 80). Called without options, the scan defaults to 2,600 elements and 120 issues;aa-scan-outlineraises the issue default to 250. core/finding.jsmaps audit issues, contrast results and scan issues onto one finding shape (fromA11yIssue,fromContrastResult,fromScanIssue), which the Findings tool sorts by severity.runtime/page-overlay.jsdraws the outlines in its own shadow root throughcreateOverlayHost(), built withcreateElementonly. Pins are numbered in the list's order; the selected finding's card offers the nearest passing text color, Try the fix (an inline color preview put back on undo or close), Copy CSS and Next; the dock closes with Done or Escape. No class, attribute or style of the page is otherwise touched.a11y/store.js(IndexedDB scan history) and theanalysis*.jshelpers are shipped and tested but not imported by any runtime code yet.
11. Tool panel responsibilities
+| Panel id (label) | Runtime contract |
|---|---|
pick (Picker) | Mounts the color picker (split in the popup,
stack in the panel); eyedropColor() tries the popup's EyeDropper, then one run
in the page with scripting; updates history and lastPick. |
palette (Page palette) | Page extraction, four modes, strip or grid, clipboard exports, SVG copy, PNG and ASE downloads, Save and Open. |
image (Image) | Reads 6, 8, 12 or 16 colors from a dropped, pasted
or browsed image, or from captureVisibleTab. |
harmony, shades, convert | Deep tools behind the Picker: nine harmony schemes, Tailwind/Material/tint/shade/tone scales with exports, and the ten-field converter. |
gradient, blender (Mix) | Linear, radial and conic gradients with sRGB, OKLCH and HSL interpolation; mixing in sRGB, Linear RGB, LAB, OKLAB or HSL and six blend modes. |
contrast | WCAG rows, APCA tiers and readable sizes, a color-vision check, fixes, suggestions, Swap and Copy report. |
vision | Sends aa-vision and
aa-vision-side; Capture downloads the visible tab as a PNG. |
scan (Audit) | Sends aa-scan-page with the
scanDeep limits, renders the score, counts and numbered rows, drives the
overlay with aa-scan-outline and aa-audit-select, and copies JSON
or CSV. |
findings | Pools audit, contrast and inspector findings through
window.AAFinding. |
inspect | Drives the aa-inspect-* messages and renders
Overview, Styles, A11y, DOM and Live CSS from the snapshot. |
tokens | Reads up to 4,000 elements: 240 custom properties, 8 fonts
and 16 type sizes; exports CSS, W3C tokens, Tailwind @theme or JSON. |
snippets | The aa_snippets vault: search, This site,
Copy all, Export file, Clear all. |
history, library | Stored picks, saved colors and palettes, JSON export to the clipboard. |
launch (On the web) | Fourteen auricartisan.com routes, each in a new tab. |
12. Shared components and injected UI
+color-picker.jsexportsColorPicker,createColorPicker,mountInlinePicker,initAllColorPickers,enableAutoColorPickers,disableAutoColorPickers,configureColorPickers,setColorPickerTheme,parseColorandcolorMath. It has three shapes: a 296 px popover on color inputs, split in the popup's Picker, stacked in the side panel. An input withdata-cp-skipis never replaced, and it persists only on extension pages, never on a visited site.pickers.jsis an enhancer registry ({type, selector, match, create}) forselect,date,month,number,range,time,week,datetime,file,multiselect,datalist,radioandcheckbox. Values are written withsetNativeValue()plus realinputandchangeevents; lists longer thanSEARCH_THRESHOLD = 7get a search field; one debouncedMutationObservertracks the page.ui/combo.jsenhances the popup's ownselect[data-aa-combo]dropdowns with the same search rule.overlay-host.js:createOverlayHost({id, theme, accent})returns{mount, place, setTheme, destroy}, a zero-size host ondocument.documentElementwith an open shadow root and anall: initialreset. Hosts in use include#aa-pickers,#aa-color-pickersand#aa-context-menu.context-menu.jsbuilds one scene per right-click (edit, colour, selection, image, media, link, page or element), keeps its quick bar and layout inaa_cm_prefs(default quick barback,forward,reload,copy-url,copy-shot), offers Inspect in side panel outside Firefox, and stands down on Shift, a page that already handled the event (withcmStepAside),data-aa-no-ext-menu,data-native-context-menu,<meta name="auric-extension-menu" content="off">,[data-aa-own-menu]and auricartisan.com. It usescreateElementonly, so it works under Trusted Types.core/dom.js,core/events.jsandcore/utils.jsare small shared helpers;core/finding.jsis the finding model.
Injected UI follows fixed rules: floating UI lives in a shadow root; anything that must sit in the page is inline-styled; nothing touches the site's storage; the host page is never translated; the audit never audits the extension; and turning a feature off tears down all of its listeners, observers and replaced controls.
13. Translation and locales
+- Runtime engine.
packages/i18n/i18n.jstranslates by text: a key is the whitespace-collapsed English of a segment, a text node or a translatable attribute, looked up inlocales/hi.jsonand then in the patterns oflocales/patterns.hi.json. Re-running over translated DOM matches nothing, which keeps itsMutationObserverfrom looping. - Boot.
boot.jsimports the engine and dictionary only when the language is not English;aa_settings.langis the setting and theaa_langlocalStorage mirror stops a Hindi popup from painting English first. - Pages. In a content script the engine starts with no root; only surfaces
registered through
i18n/overlay.jsare translated, never the host page. Values, format names and standard names are markeddata-no-i18n. - Browser strings.
manifestMessages()andbuildMessages()generate_locales/enand_locales/hifrom the samehi.json, following the browser's own language. The background translates its eight menu titles with a flat lookup in the same dictionary. - Workflow.
npm run i18n:extensionharvests strings and reports missing Hindi; add the translation tohi.json, or a pattern for strings built from live values.
14. Permissions, privacy and security
+| Permission | Why it exists |
|---|---|
<all_urls> host access |
The content script and the page tools act on whatever page the user is on. |
activeTab |
The current tab when the user opens the popup, a shortcut or a menu item. |
scripting |
sendContentMessage's fallback injection, the in-page eyedropper and
palette extraction. |
storage |
Settings, history, library, snippets, pinned tools, menu preferences and the last inspection. |
clipboardWrite |
Copy buttons in the popup and in page overlays. |
contextMenus |
The items in the browser's own right-click menu. |
sidePanel (Chromium) |
The docked workspace; Firefox's sidebar_action needs no permission. |
clipboardRead, downloads, sessions (optional) |
Paste, Save as and Reopen closed tab in the custom menu, requested only when it is
turned on; aa-perms reports which are granted. |
The privacy model has no network requests of its own (no analytics, telemetry or remote code),
no accounts, no writes to a website's storage, and page-changing features that are opt-in.
Outbound navigation is limited to the welcome page opened once on install and pages the user
chooses: auricartisan.com links, the palette's Open, and web search and Google Translate from the
custom menu. The Firefox manifest
declares data_collection_permissions: { required: ["none"] }; the policy is the extension privacy policy.
Security measures: allow-listed URL schemes for privileged relays, a translation gate that
rejects scripts, styles, frames, forms, event handlers and javascript:, validated
backups, a 512 KB cap on the inspector snapshot, reversible Live CSS, queued commands that expire
after 30 seconds, session-bound inspector messages, and no inline script in extension pages.
15. Build, test and release
+npm run extension:build # every app, both targets
npm run extension:build -- --app suite --target chrome
npm run extension:build:zip # --zip --published: store zips for the suite
npm run test:extension:full # build, both suites, brutal a11y fixtures
| Script | What it does |
|---|---|
extension:build | node extension/build/build.mjs;
flags --app, --target, --published,
--zip |
extension:build:zip | Writes
auric-suite-chrome-<v>.zip, byte-identical -edge- and
-opera- copies, and auric-suite-firefox-<v>.zip |
extension:icons, extension:store,
extension:screenshots | Regenerate the icons, the store artwork and the documentation images (the last two from the built suite) |
i18n:extension | Harvest strings and report missing Hindi |
test:a11y, test:a11y:run | tests/a11y/,
with or without a build first |
test:extension, test:extension:run |
tests/extension/, with or without a build first |
test:extension:stress | Build, then
runtime-stress.test.js |
test:extension:full | Build, both suites, then the analyzer's brutal a11y fixtures |
a11y:sync, a11y:sync:check | Copy
packages/data into the VS Code package, or check for drift |
Version and changelog. extension/version.json is the only place the
version lives; bump it there. 1.0.2, dated 2026-09-23, is the latest release in
extension/CHANGELOG.md. The source also contains work the changelog lists under
Unreleased: the side panel as home base with its rail, the popup as a quick launcher, the audit
drawn by runtime/page-overlay.js with numbered pins, a finding card and a page dock,
the inspector handing its details to the side panel, the Inspect in side panel
menu action, and the aa-panel port with aa-panel-open and
aa-open-panel. A build from source therefore reports 1.0.2 but includes that work,
while a store install can still show the earlier layout. At release, rename Unreleased to the
new version and date and bump the version.
Before uploading, lint the Firefox zip with npx addons-linter; it must report no
errors. Chrome, Edge and Opera take the Chromium zip, and Brave and Vivaldi install from the
Chrome listing. Safari is not built here: run xcrun safari-web-extension-converter
extension/dist/chrome/suite on macOS and build the generated Xcode project; Safari has no
side panel or sidebar.
16. Validation checklist
+- Run
npm run extension:buildbefore any test; the suites loadextension/dist/chrome/<app>/, and a stale build passes tests that test nothing. tests/a11y/build.test.js: manifests and filtered popups for 4 apps × 2 targets.tests/extension/background-commands.test.js: every declared command is routed.- The popup audits itself with the bundled engine (score 97 or more, no critical or serious
failures, in
tests/a11y/extension.test.js), and axe-core must report no violations over every panel (popup-accessibility.test.js). - The side panel must not scroll sideways from 280 px up
(
sidebar-responsive.test.js,studio-redesign.test.js);side-panel-redesign.test.jscovers the rail, the launcher and the audit overlay. - Adding a tool: three tests count 18 panels
(
popup-real-user.test.js,popup-accessibility.test.js,tests/a11y/extension.test.js). - Manually, on the built package in Chrome and Firefox: the popup, side panel and window; Pick from page with the OS eyedropper; the three optional permission prompts, declined once and then accepted; every default shortcut; pickers staying native on auricartisan.com; the Firefox sidebar, a picker, the inspector and the right-click menu; and switching to हिन्दी and back.
For workflow-level instructions, see the Browser Extension User Guide.