Simply Broken

← The Notes Layer

v1 · one layer

Notes and editing stop fighting for the same click

There were two buttons, Notes and Edit text, and two mental models for one job. This is one button and one model: the text is the editor, and a small square beside each component is the note.

Try it on a real article

Why there were two buttons

The old notes layer made a tap on a paragraph mean leave a note here. That is a reasonable design until you also want to change the words, because changing the words needs the same tap on the same paragraph. So editing arrived as a second toggle, and the two files had to negotiate: edit.js bound its handler on the CAPTURE phase and stopped propagation, purely so that a tap inside an editable block would not also open a sticky note underneath it.

Two features were competing for one gesture, so a mode had to arbitrate. Split them by TARGET instead and the competition disappears: the text is one target, a 14 px square beside it is another. Nothing has to be arbitrated, and one button can turn the whole layer on.

The two gestures

Click the text

The block becomes editable where you clicked, with the caret at the tap. Type over it. Every keystroke is saved as you make it, so there is nothing to commit and nothing to lose. The export carries was and now.

A spec is a dynamic tool, not a static template

Enter is a regular Enter. Nothing needs confirming.

Click the square

A sticky opens under the component and saves as you type. The square fills yellow the moment it holds something, so a page shows you where you have been.

A spec is a dynamic tool, not a static template
This buries the point. Lead with it.

Empty square: nothing here yet. Yellow: a note.

One square per component

A component is a block that a note could sensibly be about: a paragraph, a heading, a card, a table, a figure, a diagram. The rule is outermost wins, so a card gets one square rather than one per paragraph inside it, and a list is one component rather than one per bullet. On the sample article that is 70 squares for 70 components, asserted rather than eyeballed.

They line up in one rail beside the reading column. The first build hung each square off its own component's right edge, which looked accidental, because a short heading, a full-width rule and a paragraph have three different right edges. The rail now sits at the MEDIAN right edge of the text blocks: measured on the sample, 56 of 70 components end at 673 px and two full-bleed outliers end at 1202, so the maximum put the rail at the page edge, 530 px from the prose it annotates. Where there is no room for a rail at all, on a phone, each square tucks into its own component's corner instead.

What "the rail" means

Turn Notes on and the squares stack into a straight vertical line down the page. That line is the rail. The only choice it presents is how far right it sits, and there are two candidates: hard against the page edge, or just past the end of the text.

It sits just past the text. At the page edge the squares were 530 pixels away from the paragraph each one belonged to, which read as furniture rather than as part of the writing. Nothing to decide here unless the current position bothers you.

What it replaces

feedback.js and edit.js become one notes.js. One button instead of two, one store instead of two, and one Copy that hands over notes and edits together, still grouped by page across the whole site.

Nothing written before is lost

Notes used to be keyed by a POSITIONAL index, and this file scans the page differently, so every old id would silently re-point at the wrong element. They are re-anchored by the quote each note already stored instead. Anything that cannot be matched is kept as unanchored and still appears in the export, labelled, rather than being dropped. A note is your own words; losing one to a refactor is not a trade worth making.

Checked, not assumed

WhatHow it was proved
Squares stay hidden until Notes is pressedcomputed display read before and after the toggle
One square per component, none nestedcounted against the component list, at both widths
Every square is clickableasserted no square has a zero-size box. This caught a real bug: an HTML button appended inside an <svg> is in the wrong namespace and renders 0x0, so the diagram's square could never be tapped. Those components get a sibling square now.
The rail is one columnx positions of all 70 squares spread 1 px at 1280
A square opens a sticky, and fills yellowreal mouse press, then typed text, then the class re-read
Clicking text edits it, and records was/nowreal press, typed text, then the store re-read
Both survive a reloadnavigated away and back, then re-read
No horizontal overflowscrollWidth equals the viewport at 1280 and 390
Waiting on you

This is one page, so it can be judged before it is everywhere. Nothing else on the site has changed: every other page still carries the old two-button layer.

Settled by Amit, 2026-08-15: every paragraph is a component and carries its own square. And Enter is a regular Enter: an edit is never waiting to be committed, it is saved on every keystroke and is already part of what Copy hands over.

Try it on a real article