A link owner can now flip a share link to view only and set how long it lives, from the dashboard row or a new share popover in the viewer — the room enforces both everywhere a write can land, not just in the toolbar.
A share link used to be one setting: whoever had the URL could edit the room.
Loosening that meant deciding what "read only" actually covers, because a
socket is not the only way to write to a room — the REST endpoint is what
realtime sync falls back to when the socket drops, and it's what an anonymous
API caller or an MCP agent hits directly. Both paths now ask the same
question, canEditLink(), so a toolbar that stayed hidden was never the only
thing standing between a viewer and a write.
The owner's expiry needed its own column rather than reusing the room's
existing one, because an anonymous visitor's re-save overwrites that value on
every load — an owner's choice has to survive being visited by someone who
never sees the settings panel at all.
New
Anyone with the link: can edit, or can view. A link owner could claim a room but never change what the link itself allowed. The dashboard row and the viewer's share popover now carry a Can edit / Can view toggle. Switch a link to view only and every open tab loses its toolbar and drawing tools within the same session — the room pushes the change live rather than waiting for a reload.
Set when a link expires. Alongside access, the same panel sets an expiry: 1 day, 7 days, 30 days or never. It is the owner's own deadline, so it survives an anonymous visitor re-saving the room, and it is undone the moment the owner releases the link back to anyone with the URL.
Improved
A read-only refusal says so. A write to a view-only room used to look identical to a write to a room that had vanished — the extension, the viewer and an MCP agent all read back the same generic failure. Each now reports the refusal in its own words, so an agent told to leave a note knows the room is read only rather than hunting for a broken id.
Fixed
The Expires row shows a real date. The info panel's Expires row read "90 days after last view" with no date attached, and ignored the 90-day idle window whenever a custom expiry was set. It now shows the actual date the room disappears on, computed the same way the daily cleanup decides it.
The sign-in email survives dark mode. Gmail and Apple Mail auto-invert an email with no dark palette of its own: the sign-in link's dark button and white page flipped to a washed-out button on a charcoal page. The email now declares its own palette so it renders the same everywhere, and the fallback link is set in mono so a long URL doesn't wrap mid-word.
Paste any URL at marklayer.app and annotate the live page in your browser. No install, no account, no sign-up. Recipients of your share links don't need to install anything either.