Skip to content

Releases: Chevalet/chevaletStickNoteExtension

v0.0.16 — on the store, at last

Choose a tag to compare

@aturzone aturzone released this 08 Sep 20:43

This is the one on addons.mozilla.org. If you installed from the store, Firefox updates you on its own — nothing to download here.

It is 0.0.14's code. The only reason it has its own number is a mistake worth writing down.

Seven releases reached nobody

Everyone who installed from the store has been on 0.0.8 since it was approved. 0.0.9 through 0.0.15 were built, signed, tagged and published here, and not one of them reached a store user.

Mozilla signs through two channels. Unlisted produces a file you install by hand. Listed is the store, and it is the only route Firefox ever updates anyone from — a GitHub release is a place to download a file from, not a distribution channel.

The channel is chosen in two places, and both were missed:

  1. tools/sign.mjs defaulted to unlisted — correct when it was written, for a listing still in review, and never revisited after approval. That took 0.0.9–0.0.13, and 0.0.14 deliberately.
  2. Once that was fixed, the Developer Hub's upload form asks the same question again, on its own page, before the file: On this site or On your own. 0.0.15 took the second.

A version number is spent globally across both channels, so none of the seven can be reclaimed. The listed history reads 0.0.8, then 0.0.16.

The fix is not "read the page more carefully". pnpm amo:status asks AMO which channel every version is actually in and prints it:

version    channel     status     created
0.0.16     listed      public     2026-09-08 <- reaches store users
0.0.15     unlisted    public     2026-09-08
...
0.0.8      listed      public     2026-09-04 <- reaches store users

What store users get, all at once

Eight releases. CHANGELOG.md is written for them; the short version:

  • Typing is saved as you type. A note you wrote and reloaded used to come back empty unless you had pressed a formatting shortcut while writing it.
  • Notes stop leaking across a single-page app's routes.
  • Notes going transparent and unresponsive — hold-Alt stuck on, fixed in 0.0.14.
  • Persian, as a language you choose: the whole interface, right to left. English stays the default.
  • Where a note shows: this page, this section, the whole site, or every page.
  • Hold Alt to read and click the page under your notes.
  • Edit a note from the cabinet, and give it a name separate from its text.
  • Version history, scheduled backup, import that writes, Markdown and HTML export.
  • Six typefaces bundled — nothing fetched from the network.
  • The dark theme redrawn as graphite, every text-on-background pair measured for contrast.

Verification

746 unit tests, web-ext lint 0 errors / 0 warnings / 0 notices, and 38 checks in a real Firefox across four harnesses. source-0.0.16.zip was unpacked on a separate path, installed, built, and diffed against the submitted package — byte-for-byte identical.

v0.0.14 — notes going transparent and unusable

Choose a tag to compare

@aturzone aturzone released this 08 Sep 20:43

The transparent-notes fix, signed for installing by hand.

If you use the store version, ignore this one — 0.0.16 is the same code, and Firefox updates you on its own.

The bug

Notes could go transparent and stop responding to clicks, usually right after creating one, with nothing but a page reload to bring them back.

That was hold-Alt stuck on. Holding Alt is meant to make the notes translucent so you can read and click the page underneath — but it trusted keydown and keyup to arrive in pairs, and on Windows they do not: Alt reaches for the menu bar, so the release can be delivered to browser chrome and the page never hears it. Since the way to make a note is Alt + double-click, it clustered exactly where the report said.

Four ways out now — a click, any keystroke, the window losing focus, the tab being hidden — plus a 250 ms hold before anything fades, so creating a note no longer flashes every other note translucent.

spikes/firefox-ghost.mjs went from 5 checks to 12; three of them hold Alt with no keyup ever and then recover from it.

Install

about:addons → gear → Install Add-on From File → pick the .xpi. Signed by Mozilla, so it survives closing Firefox. Your notes are kept — the database is separate from the extension files.

v0.0.13 — this section, real bold, live cabinet

Choose a tag to compare

@aturzone aturzone released this 06 Sep 09:47

Install: download chevalet_note-0.0.13.xpi below, open about:addons, click the gear →
Install Add-on From File. Signed by Mozilla. Installing over an older version keeps every
note.


"This section" — the fourth place a note can show

A note's settings now offer This page, This section, This whole site and Every
page
. The section is every page whose address starts the same way, and it is worked out from
the page you are on — so the option names it: This section (/blog/).

That label matters. "This section" means /blog/ when you are reading an article and the whole
host when you are at the top of a site, so the picker shows which one it will use rather than
leaving you to guess. The note's panel and the extension's core compute it with the same
function, so the label cannot promise one thing while the click does another.

This was the last reachable scope kind: Scope has had five since the first release and four
of them could not be created at all.

Bold is really bold

**bold** in a note set in Handwriting or Grotesk was the browser smearing the regular
letters. Both families ship a drawn bold, so both are bundled now — as the two Persian faces
already were.

Bangers and Permanent Marker are drawn at one weight and have no bold to bundle, so synthesised
bold stays there. A test reads the font packages and enforces both directions, so a family that
gains a bold upstream shows up as a failing test rather than as a smear nobody notices.

An edit in a tab reaches an open cabinet

The cabinet could already reach a tab — rename, restore a version, edit the text. Now the other
direction works too: type in a note and an open cabinet updates. It will not redraw while a
dialog is open or while you are typing in the search box.

Under the hood

  • cs/renderer.ts has tests — 17 of them. It is the module both of the bugs reported
    against 0.0.10 lived in, and it had none. Put the single-page-app fix back out and three of
    them fail.
  • A third language is now cheap. English is the source and every other language is optional
    per string, with a fallback per key — so a language can arrive half-finished and be useful
    from the first string. Persian is complete and a test keeps it that way.
  • Fixed: the background re-broadcast the settings to every tab on any local storage write.
    Harmless before; with a live-update counter it would have fired twice a second while typing.

736 tests · 31 checks against the real extension in a real Firefox, each with a control ·
content script 36.5 kB gz of a 38.0 budget · web-ext lint 0/0/0.

v0.0.12 — Persian, one settings home, and the update button works

Choose a tag to compare

@aturzone aturzone released this 05 Sep 17:57

Install: download chevalet_note-0.0.12.xpi below, open about:addons, click the gear →
Install Add-on From File. Signed by Mozilla, so it stays installed. Installing over an
older version keeps every note.


Check for update no longer sticks on "Checking…"

The options page asked the background to request the host permission, passing a
fromClick: true flag in the belief that it carried the user gesture across the message. It
does not — so that request could never be granted. The page asks in its own click handler now,
and the button has a fifteen-second deadline, so it always comes back.

What made it hang forever is not established, and the code says so: the control did not
reproduce it under WebDriver. The fix is therefore two things — the correct flow, and a
deadline that makes the symptom impossible whatever the cause.

Persian, as a choice

The whole interface: the cabinet, every settings pane, the keyboard reference, the popup, the
options page, and a note's own toolbar and panel. About 230 strings, mirrored right to left —
the cabinet moves to the right, the drawer pulls flip, the scrollbar changes side.

English stays the default. Following the browser is an explicit option, not the starting
state. Cabinet → Settings → Backup → Language.

Before this, the Language setting did nothing at all inside the extension: t() asked
browser.i18n, which answers in Firefox's locale rather than ours. It appeared to work only
in the development harnesses.

One home for every setting

The options page carried its own copies of Where notes appear, Closing a tab, Keeping and
deleting, Backup and Language — every one also in the cabinet, laid out differently, so the two
disagreed about what the settings even were. The cabinet is the home now. The options page is a
way in, a version number, an update check, and two pieces of prose.

Where a note shows

Scope had five kinds and only one could ever exist. Three are a feature now, in a note's own
settings: this page, this whole site, every page. A note on the whole site appears
on every page of it, in the same place.

Hold Alt

The notes go translucent and stop taking the pointer, so you can read and click the page
underneath. A link under a note is clickable while Alt is held.

The rest

  • Edit a note's text from the cabinet — the last thing it could not do. The previous text
    is kept as a version, so History can put it back.
  • A dark theme that is graphite rather than black, with the menu changing when the theme
    does. Every text-on-surface pair in both themes is checked by a test.
  • Notes can have a name, separate from their text: in the note's header, in the cabinet, in
    search, and as a heading in an export.
  • Fixed: the per-domain note counts were clipped off the cabinet's edge; a hidden settings row
    still drew a rule; a dropdown on the options page looked exactly like a text field.

697 tests · content script 36.2 kB gz of a 38.0 budget · web-ext lint 0/0/0 · and four
harnesses that drive the real extension in a real Firefox: the pages, a page with notes on it,
persistence across a reload, and hold-Alt. Each has a control that fails when the bug is put
back.

v0.0.11 — typing is saved, and a note stays on its own page

Choose a tag to compare

@aturzone aturzone released this 05 Sep 12:47

Install: download chevalet_note-0.0.11.xpi below, open about:addons, click the gear →
Install Add-on From File. Signed by Mozilla, so it stays installed.


Notes were not being saved as you typed them

That is the release. NoteView told the store about a text change when you ticked a task box,
attached an image, pressed undo, or used a formatting shortcut — and never when you typed.
So a note you wrote and then reloaded came back empty, and the only way to save your words was
to press Ctrl+B while writing them.

It shipped four times because of how it was being checked. The development playground reached
into the note and added its own keystroke listener, so the one tool used to answer "do notes
survive a reload?"
was answering about behaviour the extension did not have.

The rule that came out of it: a test harness may stand in for what it cannot have, and must
never add behaviour the product lacks.

A note followed a single-page app from one route to another

Reported: a note made on /blog also appeared on /blog/what-is-defi. The URL matching was
never wrong — a pushState route change unloads no document, so nothing told the note's page
that the page had changed. It now finds out, and works out which notes belong there.

Notes can have a name

Separate from the text inside them. Set it in the note's own settings (the sliders button, or
press S), or from Rename… in the cabinet. It shows in the note's header, in the cabinet
instead of the first line, in search — where it outranks everything else — and as a heading in
an exported file. Renaming from the cabinet reaches a tab that has the note open.

The dark theme is lighter, and the light theme's menu is not black

The first graphite ramp started at #1c1a17 — a colour by the numbers, black on a screen. The
floor is #2e2b28 now, about two and a half times the light. And the light theme's cabinet was
darker than the dark theme's, which is absurd once said out loud: it is kraft board with ink
on it now. Every text-on-surface pair in both themes is checked by a test.

Six typefaces, bundled

Vazirmatn and Estedad at two weights each, plus Marker, Display, Handwriting and Grotesk. The
Type menu has offered all six since the first release and assets/fonts/ was empty the whole
time, so choosing one did nothing you could see. Persian no longer depends on what your
operating system happens to have. Each face loads only when a note uses it.

The rest

  • Import writes now. Reading, checking and planning worked; applying did not. A backup you
    cannot restore is not a backup.
  • Export as Markdown or as one HTML page that fetches nothing from the internet.
  • Version history — the only undo that survives closing the tab. Select one note in the
    cabinet and press History.
  • Scheduled backup to your Downloads folder, on a ring of three files. It asks Firefox for
    permission to save files only when you switch it on.
  • Fixed: the per-domain note counts in the cabinet were clipped off the edge; a key cap in the
    shortcut reference was a slab holding one letter; a dropdown on the options page looked
    exactly like a text field.
  • web_accessible_resources is empty — the fonts were exposed to every page for no reason.

679 tests · content script 33.7 kB gz of a 36.0 budget · web-ext lint 0 errors, 0 warnings,
0 notices · nine checks against the real extension in a real Firefox, each with a control.

v0.0.10 — every shortcut, on every keyboard layout

Choose a tag to compare

@aturzone aturzone released this 04 Sep 22:18

Install: download chevalet_note-0.0.10.xpi below, open about:addons, click the gear →
Install Add-on From File. It is signed by Mozilla, so it stays installed after you close
Firefox.


One line was breaking every shortcut on a non-Latin keyboard

Three separate reports — S did not open a note's settings, Ctrl+Z did nothing, and the
Ctrl+B family did not exist — were one cause. Every letter shortcut was compared against
KeyboardEvent.key, which is the character the active keyboard layout produces. On a
Persian, Arabic, Cyrillic or Greek layout the physical S key does not report s, so S,
C, D, L, M, P, E, Ctrl+Z and Ctrl+Y all silently did nothing — while Backspace,
Delete, Escape and the arrows kept working, because their values do not depend on the layout.

That lopsided pattern was the whole clue. Shortcuts now match on the physical key, with a
Latin layout still winning where it has an opinion, so Dvorak behaves the way a Dvorak user
expects. Measured in a real Firefox: 45 checks, control first, with a layout matrix across
Persian, Arabic, Cyrillic and Greek plus a Dvorak counter-case.

New

  • Formatting while you type — bold, italic, strikethrough, code, links, quotes, bullet /
    numbered / task lists, headings, insert-date, clear-formatting. Each is one undo step. There
    is deliberately no Ctrl+U: markdown has no underline.
  • A settings button in every note's header. S used to be the only way in, which was no
    way in at all on a non-Latin keyboard.
  • A dark theme for the cabinet, the popup and the options page — follow the browser, or
    force dark or light. The switch is at the foot of the cabinet.
  • A keyboard reference that reads the browser's own bindings, so it cannot disagree with
    what you set in about:addons.

Fixed

  • The settings pane in the cabinet was a trap: clicking anything else did not leave it.
  • Drawings were lost on reload. They were sent, and dropped one line short of the screen.
  • The Movement setting was read by nothing at all. It is now a ceiling on every note's physics.
  • Cabinet settings never reached tabs that were already open.
  • Two sliders showed the wrong numbers and could write values a note could not use.
  • Undo put the caret at the end of the text, always — ShadowRoot.getSelection() does not
    exist in Firefox.
  • Three controls that changed nothing are gone, and the trash-retention sweep they implied
    is now real. Every remaining control is traceable to code that reads it.
  • A ghost button was acid yellow on cream paper wherever it sat on the page.
  • The popup printed the same sentence twice.

490 tests · content script 31.9 kB gz of a 34.0 budget · web-ext lint 0 errors, 0 warnings,
0 notices.

v0.0.8 — retry upload

Choose a tag to compare

@aturzone aturzone released this 04 Sep 11:28

Same package as 0.0.7, with a clean version number.

Why this exists

The 0.0.7 upload to AMO stopped at 85% (139KB of 163KB) with "There was a problem
contacting the server"
. The validator never ran — that message is a transport failure, not a
verdict on the package. Nothing was wrong with the zip; it lints at 0 errors / 0 warnings /
0 notices here, and the 0.0.4 upload passed validation cleanly.

AMO will not accept a version number it has already seen, even from a failed attempt, so this
is 0.0.8 rather than a retry. The code is identical apart from the version string.

Which file goes where

file where it goes
chevalet_note-0.0.8.zip the Upload Version page — this page takes one file
source-0.0.8.zip a later step, after Continue, when AMO asks "Do you need to submit source code?" → Yes

The source archive is not optional for us: the build is minified, and AMO requires the original
source whenever the shipped code is. SOURCE.md inside the archive is written for the reviewer.

If the upload keeps stalling

It is a 163KB file, so a stall at 85% is a connection problem rather than a size problem. Try
again first; it usually goes through on a second attempt. If it does not, docs/PUBLISHING.md
covers uploading through the AMO API instead, which is a single command and does not depend on
a browser session staying up.

Everything else

docs/LISTING.md has paste-ready text for every field in the submission form.
docs/PUBLISHING.md has the process. 414 tests,
web-ext lint --warnings-as-errors at 0/0/0.

v0.0.7 — submission-ready

Choose a tag to compare

@aturzone aturzone released this 04 Sep 11:24

Submission-ready. This is the build to upload to addons.mozilla.org.

Two files below: chevalet_note-0.0.7.zip is the extension, source-0.0.7.zip is the source
archive AMO requires because our build is minified.

What changed from 0.0.6

author and homepage_url were missing from the manifest — AMO shows both on the listing page.
default_locale was already correct and every localised manifest key resolves, which is the
rejection cause worth checking twice.

docs/LISTING.md is new: every field the submission form asks for, written out to be copied
rather than composed in the form. Name, summary, the full description, categories, tags, licence,
the data-collection answers, version notes, reviewer notes, and a four-shot screenshot list.

Spike R1 — automated, and honestly inconclusive

spikes/firefox-r1.mjs builds a probe add-on, installs it in a real Firefox, arms a
beforeunload in an isolated world and closes the tab. It reports no dialog — and so does the
control
, where the page arms its own beforeunload, which certainly prompts in a real browser.

A failed control means a useless measurement: WebDriver's Close Window command does not run
unload prompts at all. The spike stays in the repo with its control intact so nobody repeats the
approach, and docs/spikes.md now has the thirty-second human procedure with a table for
reading the result.

This does not block submission. The close-warning setting already describes itself as
best-effort, which is honest whichever way the answer falls.

Publishing

  • docs/PUBLISHING.md — listed versus unlisted, pre-flight checks, the source-archive
    requirement, what happens after review
  • docs/LISTING.md — the paste-ready text for every form field

414 tests, web-ext lint --warnings-as-errors at 0 errors / 0 warnings / 0 notices.

v0.0.6 — first LTS

Choose a tag to compare

@aturzone aturzone released this 04 Sep 11:12

First LTS. Backspace works, both AMO validator warnings are gone, and the two features that
were sitting one hook away are wired.

Install

  1. Download chevalet_note-0.0.6.zip
  2. about:debugging#/runtime/this-firefox → Load Temporary Add-on… → pick the .zip
  3. Click the toolbar icon and grant access to a site
  4. Alt + double-click on empty page space, or right-click → Add a note here

source-0.0.6.zip is the source archive for an AMO submission — see below.

The AMO warnings, fixed

data_collection_permissions did not exist until Firefox 140, and until 142 on Android, so
declaring a floor of 128 promised support that could not be delivered. The floor is now
140 desktop / 142 Android. Raising it beats dropping the declaration: "this add-on collects
no data", stated where the browser itself can show it, is the strongest line in the listing.

One logo, and it has presence now

The toolbar icon looked like a small stamp in an empty square, and the reason was measurable:
the old mark spanned 7..53 of a 64 box, so barely 72% of the frame carried ink, and its keyline
rendered at 0.4px at 16px.

Redrawn to fill 92% of the frame, nothing thinner than 3 units, marker strokes landing at
2.25px and 1.6px in the toolbar. The weight comes from the offset register shadow rather than a
fat black outline — which was the earlier criticism. The halftone and the tilt are gone: texture
at 128px, dirt at 16px.

logo-mark.svg is deleted. One logo, in the toolbar, the tab, the popup, the settings page,
the cabinet and the store listing. All nine sizes are rasterised from it by a script in a real
Firefox, so the PNGs cannot drift away from the SVG.

Settings, inside the cabinet

Every option now lives in the cabinet, in the cabinet's own idiom rather than as a form: manila
section tabs with a cut leading edge, ruled index-card paper, paper switches that slide,
segmented choices as strips of little tabs, palette swatches with the accent showing as a marker
stroke. Each control writes straight through — no Save button, because a Save button is a way to
lose work when you close the tab.

Six sections: Where · Closing · Look · Keeping · Backup · Keys. The Keys section documents
every shortcut, with S — open this note's settings as the first row.

Two gaps closed

Pasted and dropped images work. The storage was always there; the renderer never passed the
hook. They travel as bytes with a 10 MB ceiling and a decodable-type allowlist, and they are
painted into a canvas — a content script's <img src> answers to the page's CSP and would
silently fail on a strict site.

"Save as my default" does something. Held as a sparse diff, so adding a style field later
reaches every existing note instead of being frozen out. Changing it re-resolves every note in
every open tab, and each note keeps whatever it set deliberately.

Publishing

docs/PUBLISHING.md is new and covers the whole route: listed versus unlisted and why listed is
the answer (Firefox then updates it for everyone, silently), the pre-flight checks, prepared
listing copy, the screenshot list, the data-collection answers, a draft of the reviewer notes,
and the requirement that catches most first submissions — AMO needs the original source
whenever the shipped code is minified
, which ours is. source-0.0.6.zip above is that
archive.

Still open

Spike R1 — whether a content script's beforeunload actually produces a dialog on tab close —
is unanswered, which is why the close-tab warning is described as best-effort. Honest either
way, so it does not block submission. It takes a minute now: make a note, type, close the tab.

ZIP import still reads and plans without writing. Export is complete.

414 tests, web-ext lint --warnings-as-errors at 0 errors / 0 warnings / 0 notices, and
Backspace re-verified deleting in a real Firefox 155 against the real note.

v0.0.4 — Backspace works

Choose a tag to compare

@aturzone aturzone released this 04 Sep 09:28

Backspace works. Verified in a real Firefox 155, with real key events, against a real note.

It was one line

The note's shadow host was attached to document.documentElement — a sibling of <body>,
outside it — on the reasoning that a child of <html> is the hardest place for a page to
disturb.

Gecko will not perform an editing command for an editing host that sits outside <body>.
It dispatches beforeinput with deleteContentBackward, does not cancel it, and then declines
to edit: no input event, no change, no error. Text insertion takes a different path and kept
working — which is exactly why the symptom was so lopsided: a note you could write in and could
not erase in.

Measured across four hosts differing only in position and tag name:

host Backspace
<div> inside <body> deletes
custom tag inside <body> deletes
<div> on <html> nothing
custom tag on <html> nothing

The tag name is irrelevant. The position is everything.

Three wrong fixes before this one

Worth saying plainly. Every instrument I had was wrong for the job:

  • The browser I can automate is Chromium-based, and Blink has no such restriction — the bug is
    invisible there.
  • Injected key events carry no physical code, so the browser delivers them as events and
    performs no editing action. Under a synthetic Backspace every editable element on earth
    looks broken. My first "reproduction" proved nothing, and the fix that followed was
    addressing an artefact of my own test.

Two real bugs were found on the way and remain fixed — a caret that was destroyed and never
replaced, and RTL applying to the editor but not the rendered view. Neither was this one.

0.0.3's change is reverted: it removed keyboard events from the note's event containment on
a theory that measurement has now disproved. Containment is back, because it stops a site's
bare / or j/k shortcut firing while you type in a note.

What found it

Atur suggested driving a real browser, which was the unblock. geckodriver now drives the
installed Firefox, and four scripts in spikes/ narrowed it down: the structure (seven
variants, all innocent), the real note instrumented, one intervention at a time, and finally
host position. They are committed — reach for them before theorising about engine behaviour.

Also eliminated, and innocent: the closed shadow root, all: initial, pointer-events: none,
contain: style, plaintext-only vs true, ancestor transforms, the adopted stylesheet, and
four levels of nesting.

Install

  1. Download chevalet_note-0.0.4.zip
  2. about:debugging#/runtime/this-firefox → Load Temporary Add-on… → pick the .zip
  3. Click the toolbar icon and grant access to a site
  4. Alt + double-click on empty page space, or right-click → Add a note here

Unsigned, so it loads temporarily and goes when you close Firefox.

Everything else from 0.0.2 and 0.0.3

Full undo/redo (Ctrl+Z / Ctrl+Y / Ctrl+Shift+Z) over typing, colour, style, move, resize,
collapse, lock, drawing, erasing, create and delete — one ordered history, a typing run as one
step, a whole drag as one step, 1.3 µs per recorded edit. RTL per block. The update check in
settings. The diagnostics section is still there, and now mostly redundant.

404 tests, web-ext lint --warnings-as-errors at 0 errors / 0 warnings / 0 notices.