Skip to content
Message Bottle — Design
Traveling message bottles. v1 buildable slice + parked vision.

Design captured 2026-06-15 from a brainstorm. The original rough notes live on the parent Objects page. This page has two parts: the v1 buildable slice (what we build + test now) and the parked vision (the full traveling-bottle model, documented as the roadmap, not built yet).

The shape

A message bottle is a place on the web where a small conversation accumulates. The long-term vision is that bottles travel along the real paths people walk between pages — turning a bottle into the record of a journey through the web, a rabbit-hole made followable. But travel is rich and risky to tune, so we start with the stationary core (the heart of the idea) and add travel later, informed by what we learn.
The emotional target: leaving a message should feel like a small act of care for a shared place — closer to leaving a note in a trail register than posting a comment. Discovery should feel like a find.

V1 — buildable slice (build + test now)

Hypothesis being tested: do people find it meaningful to leave and discover messages tied to places on the web, and does adding to someone else’s bottle feel good? Everything else (travel, branching, scarcity economy) is elaboration on top of this — only worth building if the base resonates.
This reuses almost all of the bottle infrastructure already built (placement ceremony, per-page playhtml-channel persistence, DOM anchoring, probabilistic discovery with per-user cooldowns). The only real changes are: a bottle holds a chain of messages instead of one, and we build the chain-reading UI.

Behavior

A bottle lives on a page (stationary — no travel in v1).
You place a message via the existing sealing ceremony (drag-to-roll → card → plunge into the page slot).
Anyone who later finds the bottle can read the chain and add their own message — appending to the same bottle. A bottle becomes a small growing thread on that page.
Each message carries source attribution (author color, as today; the ECDSA pid is stored but never shown).
Discovery is probabilistic (per-user cooldowns) so encountering a bottle is a find, not a guarantee.

Reading UI (the main new build)

Opening a bottle shows the full chain of messages in order, each labeled with its author (color) — readable top to bottom.
A way to navigate the places the messages came from. In v1 every message is on the same page, so this surfaces as attribution + ‘left here’; the affordance is built to generalize so that when travel ships, the same control lets you click back through the different pages the chain crossed.
The writing UI (the sealing ceremony) is already built; v1 polishes it but the ceremony interaction is done.

Data model (v1)

A bottle = an ordered list of messages in a playhtml pageData channel keyed to the (normalized) page URL.
BottleMessage { id, text, createdAt, createdBy (pid), authorColor, pageUrl }
Bottle { id, messages: BottleMessage[], createdAt }
pageUrl is the same for every message in v1 (stationary) but is part of the schema from the start so travel doesn’t require a migration later. This is the chain substrate the whole traveling model sits on — a node in the future tree is just a Bottle (a chain).

Build sequencing

PR 1 (infra) — merge first: the chain data model + the social-experiment scaffold + the stationary place/add-to-chain plumbing, behind the BOTTLES flag. This is the substrate; get it landed and stable.
PR 2 (UX polish) — coordinate with beta launch: the reading UI and writing-UI polish, tuned closer to launch with real testing. Decoupling lets the infrastructure land without blocking on visual tuning.

Parked vision — the Traveling Bottle (roadmap, not built)

The full model we worked out. Captured so it isn’t lost; do not build until the v1 base resonates with people. Many of these rules are guesses to tune, not commitments.

Placement (origin)

Bottles are intentionally placed, not auto-spawned. Placing is scarce — a real choice / sacrifice (you only have so many). The exact economy of how you get / regain bottles is parked (‘scarce, TBD’). Candidates discussed: slow regeneration, earned-by-participation (you can only originate after contributing to someone else’s bottle — a gift economy, thematically ideal but has a cold-start problem), or one-in-flight-at-a-time.
Auto-spawning + empty bottles go away entirely. There are only bottles someone made.

The bottle as a tree

A bottle is a tree of nodes rooted at the placement page. Each node = a page the bottle has touched, carrying the message-chain up to that point. Every node is alive — findable, readable, addable. (A node is just a v1 Bottle chain.)

Travel — human-triggered (the engine)

Travel is triggered by a human adding a message, not by an autonomous timer. When someone finds a node, reads it, and adds a message, that act carries the bottle one hop onward, leaving the extended chain as a node behind.
The hop goes along a real human-walked outbound edge from the current page (reusing WWO’s existing navigation data) — not raw page links. So the bottle flows along desire paths, and the breadcrumb can highlight the actual <a> link the bottle traveled through.
Among eligible edges, pick weighted-random (favor well-walked edges, not deterministic) for variety.
Why human-triggered: it makes growth rate-limited by real human attention (one contribution = at most one new hop), which bounds spread naturally and keeps the backend safe — no autonomous exponential forking while everyone sleeps. It’s also more true to ‘message in a bottle’ (a bottle moves when someone picks it up). An optional slow, single-hop, non-forking autonomous drift could be added later as flavor so very quiet bottles don’t sit forever — trivially bounded, not the engine.

Branching

Adding to different nodes grows different branches. Adding to the same node by different people forks it (multiple onward hops from one page).
Branching is bounded because each new branch costs one human action.

Loops

Block revisits per-branch: a single branch / path can’t revisit a page already in its own path (kills the degenerate A→B→A→B tight loop), but different branches of the tree can reconverge on hubs (so popular index/hub pages aren’t amputated from the bottle’s spread).

What you see on a page

A live node of a bottle that’s passed through: openable, readable, addable. Surfaces probabilistically (per-user cooldowns) so it’s a find.
Breadcrumbs on each node: where the bottle came from (read the chain back) and where each onward branch went (follow it forward). When the hop was an on-page link, the breadcrumb glows the actual <a> link — following the bottle means walking the same path the previous person walked, link by link. The rabbit-hole made physical.
Every page the bottle has crossed keeps its node, so the web fills in with evidence of bottles over time (ample), while the live/catchable frontier stays comparatively rare (a find).

Persistence / decay

No expiry. Nodes live forever; an old one can be reactivated by a new contribution years later. (Because growth is human-gated, ‘no expiry’ doesn’t cause unbounded autonomous spread.)

Hard line (inherited from the broader WWO values)

The tool marks pages / artifacts, never users. There is no way to target a person. This is what keeps it from becoming a brigading or pile-on mechanic.

Open questions (parked — decide after the interaction feels right)

Scarcity economy — how you get / regain a bottle to place (slow regen vs. earned-by-participation vs. one-in-flight). Includes the cold-start problem for earned-by-participation.
Reading a long chain — confirmed direction: read all messages with attribution and a way to click back through the places. Exact UI for a deep chain across many pages still to design.
Same-node contention — when two people add to the same node near-simultaneously, both messages join the node; each can spawn its own onward branch. Confirm this is the desired fork behavior at scale.
Autonomous drift (optional flavor) — should untouched bottles slowly drift one hop on their own so quiet bottles don’t sit forever? Single-hop, non-forking, bounded. Not the engine.
Breadcrumb-follow fallback — link-glow works when the hop was an on-page link; needs a fallback (named link / guided hop) when the hop wasn’t on-page.

Relationship to the built feature

What exists today (the bottles social experiment) is stationary, auto-spawned, one-message. V1 evolves that same feature into chain-accumulating stationary bottles — we don’t build a separate ‘traveling-bottles’ module. ‘Combine’ is trivially satisfied because there’s only one feature; travel is a later extension of it, not a merge of two.
It plugs into the features/social/ scaffold (flag-gated, registry-listed, cherry-pickable) like the other social experiments (quarantine tape, ambient co-presence).
Want to print your doc?
This is not the way.
Try clicking the ··· in the right corner or using a keyboard shortcut (
CtrlP
) instead.