rapier-html
v1.1.89
Published
One command turns a Markdown file into one offline HTML file: the whole Rapier editor with the document inside. Opens in any browser, phone or desktop, with no install or account. Write, draw and paint watercolor, then Send back the edits to your AI agent
Maintainers
Readme
rapier-html
Give a person a document they can read, edit and keep: one command writes one HTML file that is the whole editor, offline, with the document inside.
Use it for a plan to rearrange, an illustrated guide to annotate, a draft to continue writing, or a revision to review. Text and drawings stay editable, and the file remains usable independently of a hosted workspace.
- The page writes, draws and paints, saves Markdown, exports Word, PDF and a web page, and prints, with no account and nothing fetched to open, edit or save.
--returnadds a one-use Send back address from the agent door: the person edits offline, presses Send back, and the agent reads the returned copy.--view drawopens on Draw;--propose original.mdopens on the diff of a proposed change, and the person keeps or drops each change;--by <name>says on that diff who proposed it and when.wrapandunwrapcarry a document into a page and out again, exactly, for programs.
Node 22 or newer.
npx -- [email protected] notes.md # the editor, notes.md inside it, written beside the file
npx -- [email protected] notes.md --view draw # opens on Draw: sketch and paint, the document behind it
npx -- [email protected] notes.md --view notes # opens the Notes library
npx -- [email protected] notes.md --drawing sketch.svg # carries a drawing, opened on Draw over the document
npx -- [email protected] --propose original.md proposal.md # opens on the diff of a proposed change
npx -- [email protected] notes.md --return "$RETURN_URL" --return-expires-at "$RETURN_EXPIRES_AT" # Send back
npx -- [email protected] notes.md out.html # a named output
npm install [email protected] # as a library: wrap, unwrapThe first -- is for npm, so --help reaches the command. It never overwrites a file.
For live shared editing, open the document through Rapier's MCP tools. Read the person's current text or drawing before revising it, show the attributed changes, and export Markdown or an offline editor when the result needs an independent copy. Send back returns an edited offline copy for inspection and review alongside the hosted document.
Will markers in the Markdown control agent edits: keep, append, edit.
Send an edited document back
Call document.create_return on the Rapier agent door for the document's workspace and pass its return_url
and return_expires_at as --return "$RETURN_URL" --return-expires-at "$RETURN_EXPIRES_AT", or
wrap(..., {return: return_url, return_expires_at}). Only the worker's HTTPS return route at
https://mcp.rapier.website/return/… is accepted. The page then shows Send back in Share; a page without an
address has no such action.
The person edits offline and presses Send back: the current source and filename go once, the page shows the acceptance or the worker's refusal, and it sends nothing again. The return lasts up to one day, takes one document up to 25 MiB and grants no access to the agent's workspace. After the expiry, or a refusal, Share offers Save instead; bring that file back to the assistant for a fresh return.
The agent's document.wait_for_user returns a returned receipt with the return_id, name and time;
document.get_context lists receipts; document.read_context({return_id, start: 0}) reads the source,
continuing at the returned end until complete. The returned copy stays separate from the workspace's
current document.
As a library
Save this as example.mjs in the folder you installed into and run node example.mjs:
import {readFile, writeFile} from 'node:fs/promises';
import {wrap, unwrap} from 'rapier-html';
const rapier = await readFile(new URL('./rapier.html', import.meta.resolve('rapier-html')), 'utf8');
const words = '# Hello\r\n\r\nA note about </script> and C:\\Users\\me.\n';
const page = wrap(rapier, words, 'hello.md', {view: 'draw'}); // opens on Draw, the note behind it
console.log('words back exactly:', unwrap(page).text === words);
await writeFile('hello.rapier.html', page, {flag: 'wx'}); // 'wx': never over an existing filewrap(rapierHtml, text, name, {view, drawing, drawingName, base, baseName, return: returnURL, return_expires_at})
and unwrap(pageHtml), which returns the same fields with null for what a page does not carry. Also exported:
encodeCarried, decodeCarried, main.
How the page carries the document
One <script type="text/markdown" id="rapier-document"> block at the top of the body, never executed,
read once at boot. A drawing rides in id="rapier-drawing", the text a change was proposed against in
id="rapier-base", the view to open on in the document block's data-view, the optional return URL
in data-return and its exact expiry in data-return-expires-at. The block holds no <
before / or !, no carriage return and no NUL: \\, \/, \!, \r and \0 stand for them, one
reversible pass each way, so a note about HTML is as safe as any other. A byte-order mark is kept as a
fact of the file and written back on Save.
Safety
- It never overwrites: an existing output, the document itself included, is refused, as are unknown options, a
--viewother thandrawornotes, a--drawingor--proposewith no file, a return without its expiry, an invalid expiry, an unsafe return URL and a third filename. - Nothing reports on the page's use. It reaches the network only when the document or the person asks: a linked picture or video, a plug-in on first use (maths, diagrams, PDF import, text in pictures, a letter set), or Send back. A return URL names only the worker's exact origin and route; credentials, query strings and fragments are refused.
Optional edit history
wrap(page, text, filename, {ledger, authorship}) accepts the public kit's
rapier-ledger/1 and rapier-authorship/1 objects. unwrap(page) returns the
checked parts beside its text. Neither is on by default. An authorship projection
contains only attribution of current characters; a full ledger contains deleted
text too. A wrong-text, malformed, duplicate or inconsistent part throws instead
of attaching false history. Saved Markdown written with the kit's
ledger/carried.writeDocument is read automatically when wrapping. Rewrapping a
page without parts drops its previous document's parts. Published npm files carry
their own staged MIT validator closure; no source checkout is needed.
Licence
AGPL-3.0-only (LICENSE): the page is the Rapier editor with the notices of the libraries it carries.
The Markdown standard without the editor is rapier-markdown-kit (MIT). Rapier is https://rapier.website.
BUILD.json records the page's size, SHA-256, build time and Node version.
