Medium Pool · every medium your app could speak
$npx skills add funclosure/medium-pool

Text

Words people read, quote, and search
messageThe app becomes quotable, and streaming makes it feel like it is thinking with you.
instance Streamed answerStreams, renders, never blocks

Text is the cheapest medium to ship and the one people trust most, because they can skim it, search it and copy it. Almost every app needs it, and with language models it became a live medium: the answer arrives token by token, not as a page.

The hard part is no longer showing text, it is showing text that is still being written. Half-finished markdown, growing layout, a stop button that means something.

Reach for it when

  • the content is instructions, answers, or anything people will quote
  • latency is visible and you can hide it by streaming
  • accessibility and search matter more than atmosphere
direction
both ways
substrate
DOM · ReadableStream or Server-Sent Events · aria-live

Where it bites

  • Render markdown incrementally: an open code fence or an unclosed bold marker must not break layout mid-stream.
  • Never let the scroll position jump under the reader. Only auto-scroll when they are already at the bottom.
  • Count tokens client-side for the meter, but bill on the server; the two will never match exactly.
  • Screen readers need one live region per answer, not one per token. Announce at sentence boundaries.
  • Copy buttons must copy the source markdown, not the rendered HTML.

Instances of this medium

Each is one way to build it. None of them is the medium.

Streamed answerin the pool

Streams, renders, never blocks. reference/StreamingText.ts

streamdownopen source

A markdown renderer built for streaming. Tolerates unterminated blocks mid-stream, which is the hard part of this lane.

markedopen source

Fast markdown compiler; the baseline most incremental renderers wrap.

$npx skills add funclosure/medium-pool --skill medium-text
skills/medium-text/SKILL.md
---
name: medium-text
description: "Build streaming text UI on the web. Use when adding chat, generated answers, live transcripts, or any text that arrives progressively and renders as markdown."
---

# Text as a medium

## What this medium does to the person
Text makes an app quotable, searchable, and accountable; people trust what they can copy. Streaming adds presence: the app appears to think alongside the reader rather than hand down a finished page.

## When to reach for this medium
Text is right when people will read, quote, search, or copy the result. It is the default medium; choose another only when text is a worse fit.

## Core browser APIs
- Server-Sent Events or `fetch()` with a `ReadableStream` for token delivery
- `requestAnimationFrame` or a short `setInterval` to batch DOM writes (never one write per token)
- `aria-live="polite"` on the answer container, announced at sentence boundaries

## UX rules that always apply
- First token on screen under 500 ms, or show a skeleton that says what is happening.
- Show a caret while streaming; remove it the moment the stream ends.
- A visible Stop control while streaming, and a Copy control that copies source markdown.
- Only auto-scroll when the reader is already at the bottom.

## Reference instances
Each is one way to speak this medium, cited as evidence. None of them is the medium.

`reference/StreamingText.ts` — incremental markdown renderer that tolerates open fences and unclosed emphasis, a token/latency meter, and a stop handle. Framework-free; `mount(root)` builds the UI, `unmount()` stops the stream. It uses a few layout class names from the pool's stylesheet (`row`, `btn`, `status`, `frame`); without that stylesheet the logic still runs and the controls are unstyled.

## Gotchas
- Incremental markdown must be forgiving; use a parser that can render partial input.
- Keep layout stable: reserve width for the answer column so it does not reflow as text grows.
- Do not trust client token counts for billing.