All work
In use by my friends

A place to rant

For when your head is loud.

A private journal on the web. Open it and the cursor is already waiting; it saves as you type. When you’ve written enough, it hands the whole stretch to whichever AI you already use — and turns the reply into a chapter about you.

a place to rant
A place to rant: entries grouped by day in a sidebar, a summarised chapter titled ‘Waiting on other people’, and a half-written entry in a serif typeface on a dark page
connect-src ’none’ · nothing sent
Role
Design & development, solo
Built for
Me — then my friends
Built
September 2026, about a week
Stack
HTML · CSS · JS, no framework

01Why it exists

I needed somewhere to put things down — fast, and without an audience.

Some nights I just need to rant. Not to post it, not to send it to anyone — just to get whatever’s in my head down somewhere, quickly.

The idea started with my AI journal for the iPad, which runs a language model on the device. That one lives on a single iPad. This is the version anyone can open: a web page, a link I can share.

So I made the web version, for me. Then I sent the link to a few friends — and they actually use it. Not once to be polite, but as the place they go when their head is loud. Honestly, that was a “wow” moment for me.

Each person gets their own journal, kept in their own browser. Sharing it is just sending the link; nobody can read anybody else’s.

02The key decision

No API key. No server. Any AI.

The app never talks to a model. It writes the prompt; you carry it to whichever chatbot you already use, and paste the answer back. Two pastes instead of one click — and in exchange, the page itself is forbidden from sending anything anywhere.

  1. 1

    Write

    Entries stay in your browser’s storage. Nothing to sign up for.

  2. 2

    Copy the prompt

    Every entry, tagged [E1]…[En], the last chapter’s scores, your notes, and the exact JSON schema to answer in.

  3. 3

    Ask any AI

    Claude, ChatGPT, Gemini or anything else. Shortcut buttons copy the prompt and open the chat.

  4. 4

    Paste the reply

    The app finds the JSON, repairs what it can, and checks every field.

  5. 5

    Read your chapter

    Mood entry by entry, themes, patterns, blind spots, and an honest read.

a place to rant
The ‘Close this chapter’ dialog: step one copies a prompt into any AI, step two pastes its reply back, with an optional box for context the entries don’t contain

Why do it the long way round?

  • Privacy you can check. The hosted page ships a Content Security Policy with connect-src 'none'. The browser itself refuses to let it make a network request.
  • Free for my friends. No keys to buy, no bill to split. Everyone uses the AI they already have, on the plan they already pay for — or don’t.
  • Never out of date. When a better model comes out, the app gets better without a release.
  • Context the entries can’t give. An optional note — “Mira is my best friend from uni” — goes into the prompt, and the AI is told to trust it over its own guesses.

03Try it

Chatbots reply messily. The parser doesn’t mind.

The prompt is the API contract, and the reply is the response — except it arrives with a friendly preamble, code fences, trailing commas and curly quotes. Pick a reply and run it through the same function the app uses.

What the AI sent back
Edit it, break it, paste your own.

What the app makes of it

Press “Read reply”.

The parsing is the app’s own extractJson, lifted as-is. The chapter preview on the right is simplified; the real one renders every field.

04A chapter

The pile, read back to you.

Close a chapter whenever you like. What comes back is meant to be read slowly, on a bad day: plain words, your own quotes, and an honest guess at what you can’t see from inside it.

Chapter one, ‘Waiting on other people’: a headline, an Improving trajectory, an overall wellbeing ring at 54, and the start of a mood-by-entry chart
A title, the one-line truth, and where you are.
A radar chart of seven wellbeing scores beside four strain bars, and each entry’s date labelled with one feeling
Seven scores, four strains, one word per entry.
Themes as weighted bars coloured by how they felt, then two pattern cards with evidence, a reading and a confidence level
Patterns come with evidence and a confidence level.
A blind spot backed by an exact quote, the honest read in serif paragraphs, and a pull quote of the writer’s own words
Blind spots quote you exactly.
The Mood tab: ‘Lately it’s been a lot better’, an earlier and recent average side by side, and a timeline of entry dots with a rolling average
“Is it getting better?” — answered in words first.

Real screenshots of the app, filled with an invented journal. No one’s actual entries appear anywhere on this page.

05Small things

Built for the moment you open it.

Always a blank page

Every visit opens a fresh entry with the cursor in it and the sidebar closed. You land on a page, not on everything you wrote last time.

Saves as you type

450 ms after you stop, and again when you switch tabs or close the window. Empty entries quietly disappear.

One-tap mood

Rough, low, okay, good, great — under the page, without stealing focus from the words.

Reflect on one entry

A mirror, not advice: what’s underneath, what you keep circling, and one question to sit with.

Hide the screen

⌘ . blanks the page and renames the tab “New Tab” — for when someone walks past.

Yours to keep

JSON backup, Markdown export, and chapters as PDF. A reminder appears when your last backup gets old.

06How it’s built

One file. No dependencies.

About 3,900 lines of HTML, CSS and JavaScript — no framework, no web fonts, every chart hand-drawn in SVG. It even runs straight from the file on disk.

StorageOne versioned localStorage record with in-place migrations. Two open tabs merge each other’s saves.
AI contractThe schema travels inside every prompt. Replies are extracted, repaired, clamped and coerced; a failure writes a ready-to-paste repair message.
PrivacyCSP blocks every outgoing request; pages are marked noindex.
NextReady for sync: UUIDs, tombstones, last-write-wins merges, and an export shaped like database rows.
index.html — moodPoints()
function moodPoints(){
  const ai = new Map();
  liveCheckpoints().forEach(cp => (cp.data.entry_signals||[]).forEach(sig => {
    const e = entryForSignal(cp, sig.id);
    if(e && sig.mood != null) ai.set(e.id, { v:sig.mood, feel:sig.emotion });
  }));
  const out = [];
  entriesSorted().forEach(e => {
    if(!e.text.trim()) return;
    const self = levelOf(e.selfMood), r = e.reflection, c = ai.get(e.id);
    let p = null;
    if(self) p = { v:self.v, src:"you" };
    else if(r && r.mood != null) p = { v:r.mood, src:"reflection", feel:r.feeling || null };
    else if(c) p = { v:c.v, src:"chapter", feel:c.feel || null };
    if(p){ p.t = e.createdAt; p.id = e.id; out.push(p); }
  });
  return out;
}

07Build notes

The parts worth getting right.

01

You outrank the AI

A mood can come from three places. Your own tap wins, then a reflection on that entry, then the chapter’s read of it — that’s the function above. On the chart your marks are filled dots and the AI’s are rings, so you can always tell who said what.

02

A word and its colour never disagree

The five mood words sit at 15, 35, 50, 65 and 85 — the middle of each colour band — and the same band edges turn numbers back into words. A dot labelled “okay” is always okay-coloured.

03

Chapters that fit in one paste

Past roughly 45,000 characters, chat apps start refusing a paste or quietly dropping the oldest entries. When a chapter gets that long, the app offers to close a shorter one over the oldest entries and keep the rest queued.

04

Honest about the numbers

The prompt tells the model to say when evidence is thin, never to diagnose, and never to label other people. In the app, a “Where these numbers come from” note says plainly that a small change in score is just how the AI read the words.