Tiny Little Office (tinylittleoffice.com) keeps a whole document in its URL fragment, after the #, which browsers never send to a server. You write the document as TLO text (Markdown plus a few additions), percent-encode it into a link and hand the link over. Whoever opens it gets an editor on their own copy, and the address bar updates after each edit to hold the new version.
Procedure
- Pick the app from the table below. Read only that app's reference file. It holds the shapes the app reads and one or two worked examples.
- Write the TLO to a file in your scratchpad. Copy an example from the reference and change it rather than starting from nothing.
- Build the link with the script, which packs the text the way the site does and runs the offline lint:
It prints the URL on stdout, and findings and length warnings on stderr.python3 scripts/tlo.py link deck talk.tlo --title "My talk" --by "Muninn" - Fix every finding and rebuild.
python3 scripts/tlo.py read <url>gives back the text any link holds, packed or plain, so you can edit a link you were sent. It also reads links a chat client mangled (percent-encoded, a quote glued to the end);tlo.py repair <url>prints the clean link. - Deliver. If the link is under 2,000 characters, give it as a Markdown link with a plain description. If it is longer, put the bare URL alone in a fenced code block. Chat renderers and some apps break or truncate long links, and the code block keeps it whole for copying. Put the link on its own line: Webex, for one, pulls a following quote or bracket into the link. Say that the link is the document: an edit produces a new link, and anyone holding the link can read it.
The script makes the packed form the site itself shares: #/v1/<app>/<flag><payload>, the TLO deflated against TLO's frozen word dictionary, base64url with - for 62 and a + every 300 characters so messaging apps don't break it. The site itself writes ~ for 62 and reads - as well. This script writes - because chat clients such as Webex percent-encode ~ (sometimes twice, %257E) and the site does not decode that, so the link opens empty. --tilde reproduces the site's own output. It runs 35–50% shorter than the readable form. --title and --by go into the document's head. --plain gives the readable /<app>/#title=…&doc=… form instead, which the site also opens and packs on arrival.
Apps
| App | Reference | For |
|---|---|---|
write |
references/write.md | Letters, memos, résumés, invoices, contracts, a table that adds up |
outline |
references/outline.md | Nested ideas; the same tree can open as slides, a mind map or an org chart |
deck |
references/deck.md | Slides, plus format: poster / zine / booklet / brochure / comic / badges |
sheet |
references/sheet.md | Tables with formulas, bar/line/pie/sankey charts, named-cell models |
calc |
references/calc.md | Sums with names, unit conversion, y = f(x) graphs |
draw |
references/draw.md | Boxes and arrows on an 8px grid; pixel art |
diagram |
references/diagram.md | kind: mind, org, family, lanes, timeline, venn, seating, net |
anim |
references/anim.md | A drawing with keyframes |
cal |
references/cal.md | Events, repeats, time zones; view: gantt for schedules |
trip |
references/trip.md | Stops with lat/lon and notes on a map |
Load these only when needed. references/api.md covers file downloads (view=pdf|pptx|xlsx|…), encrypted short links, the JS API and npm CLI, password-sealed links and the official lint's full finding list. references/editors.md lists keyboard shortcuts for driving the editors in a browser.
Routing: numbers go in sheet, quick arithmetic in calc, prose in write, a tree of notes in outline, anything presented in deck. A diagram lays itself out, so prefer diagram over draw whenever one of its kinds fits. Tasks over weeks go in cal with view: gantt.
The URL
https://tinylittleoffice.com/<app>/#title=<title>&doc=<TLO, percent-encoded>
- Parameters go after
#, never after?. - Optional parameters:
by=(who made it, an unverified claim),view=(pdf,png,html,md,tlo, the app's own formats such aspptx,xlsxorics;embedfor an iframe;showto open a deck presenting). - A head line
app: sheetletshttps://tinylittleoffice.com/#doc=…work without the app in the path. - Length: QR codes hold 2,953 characters. Encrypted short links hold up to 12,272 (see api.md). Past 2,000, some chat apps cut the link.
TLO in one table
Write ordinary Markdown: headings, paragraphs, - and 1. lists nested by two spaces, - [ ] tasks, > quotes, pipe tables, **bold**, *italic*, `code`, [words](url), and footnotes as ^[note]. TLO adds the following:
| Write | Means |
|---|---|
--- / key: value / --- at the top |
The head: title, by, theme, chart, kind, zone, format… |
{#id .class key=value} at line end |
Attributes: {.title}, {.two}, {due=2027-03-01}, {color=green every=week} |
Price:money in a table header |
Typed column: text number money percent date time check url rich long icon name option |
~ A -> B: label |
A connection (->, <-, <->, --) |
```sheet … ``` |
Another app's document embedded here (any of the ten ids) |
==hi==, ++under++, :rocket: |
Highlight, underline, Lucide icon by name |
A --- between blocks starts the next slide, page or card. Any table is a live spreadsheet. Nothing is fetched from the web:  renders as a plain link.
Rules agents break
- Whitespace is content. Nesting is two spaces per level, and a dropped space flattens the tree. Never hard-wrap a paragraph, because each line break is kept.
- One thing per slide. A slide with a fence (chart, diagram, table) shows only that fence under its headline, and bullets on the same slide are dropped. Put the commentary in
>notes or on its own slide. A{.title}slide takes a line or two, not a list. - Commas split lists. In Venn and seating lists, "2,000 cases" becomes two things. Write 2000.
- Diagram things are short names. Two to four words each. Connection ends must match a listed name exactly (the text before
|). - Embed, don't link. Put another document inside as a fence rather than linking to a second TLO URL.
- A link is a copy. There is no shared live document. For a sign-up sheet or a form, tell people to send their edited link back. A short link is frozen once made.
Verifying
scripts/tlo.py lint is an offline subset of the official checks: fence-bullets, title-long, title-list, body-over, edge-end, edge-unused, net-colon, comma-number, label-long, doc-link and length. It is fast and needs no network. It does not measure rendered text or evaluate formulas. When Node is available and running third-party npm code is acceptable, npx tinylittleoffice lint <link> and measure run the real layout code and also catch formula-error, label-over and exact overflow (see api.md).
If a finding persists, the fix is in the TLO, not the URL. Re-read the app's reference rule for that shape.