Typography philosophy · the long version

Every post,
as if a thoughtful editor were about to print it.

Lanai treats every post as if a thoughtful editor were preparing it for display — but never modifies the underlying record. Cleanup happens at the rendering layer, the original is always one tap away, and the user can turn it off. Here's the spectrum, and where on it we apply each tier.

The architectural rule

All cleanup happens at the render layer. The post record never changes.

The data model in BlueskyModels stores the post body exactly as authored — as RichText with raw UTF-8 byte-offset facets. Cleanup takes a RichText and a context, and returns a display-ready AttributedString. Round-tripping a post through cleanup is a one-way display transformation — the original is never lost.

  • Other clients see the original. Lanai's cleanup is invisible to anyone not using Lanai.
  • The user can always reach the source. Long-press → "Show original" reveals the raw text.
  • Composing a reply never auto-includes Lanai's transformations. What you type is what you post.
  • Copy defaults to original; "Copy formatted" is a long-press option that copies the rendered version.

The six tiers

From "render correctly" to "transform editorially."

Typographic intervention exists on a spectrum from doing nothing to doing a great deal. We define six tiers explicitly so we can be deliberate about where each gets applied.

0
Tier 0

Render correctly.

The baseline. Respect Unicode. Don't break what the author wrote.

Always on, every surface, no toggle.

Em dashes display as em dashes, not as `--`. Emoji at appropriate sizes. Bidirectional text handled. Grapheme clusters preserved. Mentions, hashtags, and links rendered from facet metadata. This is not cleanup; it's the absence of carelessness.

As authored
Hello — world.
In Lanai
Hello — world.

We render what was authored. We don't substitute.

1
Tier 1

Display-bug recovery.

Detect and reverse rendering corruption.

Always on, every surface, no toggle.

Mojibake from incorrect encoding (`’` → `'`). BOM characters that snuck into the post body. Zero-width joiners that are clearly artifacts of copy-paste rather than intentional emoji sequences. Non-breaking spaces in contexts where they break layout. The author didn't write `’`; they wrote `'` that got corrupted.

As authored
Won’t.
In Lanai
Won't.

Mojibake recovered to the character actually authored.

2
Tier 2

Whitespace normalization.

Trim accidents at the boundaries. Touch nothing in the middle.

Always on, every surface, no toggle.

Leading and trailing whitespace trimmed. Runs of three or more newlines collapsed to double newlines (preserves paragraph breaks; removes accidental gaps). Trailing whitespace stripped from line ends. Critically: never collapse internal whitespace, never modify indentation, never touch ASCII art structure.

As authored
Hello. Goodbye.
In Lanai
Hello. Goodbye.

Boundaries normalized. Paragraph break preserved.

3
Tier 3

Smart quotes and dashes.

Genuine cleanup. Improving what the author wrote.

Default on in the timeline. User-toggleable in settings.

Convert straight quotes (`"` and `'`) to curly. Convert double-hyphens (`--`) to em dashes. Convert triple periods (`...`) to ellipses. Skip cleanup inside text that looks like code, inside URLs, and inside facet ranges. Apply locale-aware conventions when the post's `langs` field indicates non-English.

As authored
She said "hello" -- finally.
In Lanai
She said “hello” — finally.

Straight quotes curl, double-hyphen becomes em dash.

As authored
Run `git --no-edit`...
In Lanai
Run `git --no-edit`…

Backtick code block preserved; trailing dots become an ellipsis.

4
Tier 4

Light typographic refinement.

The editorial layer. Hair-spaces, locale quotes, real minus signs.

Always on in Reading Mode. Always on in image exports. Never in the timeline by default.

Hair-space adjustments around em dashes. Locale-aware quotation marks (French guillemets, German lower-quotes, Japanese brackets). Proper minus signs in numerical contexts. Multiplication signs in dimensions. Degree symbols, fractions, trademark and copyright symbols. Real editorial transformations — each can backfire on edge cases — applied where the user has explicitly opted in.

As authored
« Bonjour », a-t-elle dit.
In Lanai
« Bonjour », a-t-elle dit.

French guillemets get their thin spaces, in French.

As authored
It costs -5C.
In Lanai
It costs −5 °C.

Hyphen becomes a real minus; degrees become a degree sign.

5
Tier 5

Layout and editorial enhancement.

Pull quotes, hanging punctuation, optical alignment, hyphenation.

Reading Mode and image exports only. Never on the timeline.

Pull quotes for sentences the user selects. Hanging punctuation that pulls opening quotes and certain glyphs into the margin. Optical margin alignment for visual balance. Justified text with proper hyphenation. First-line indents on very long posts. Widow and orphan control so the last line of a paragraph never strands alone at the top of a column.

As authored
The opening quote lives inside the column.
In Lanai
“The opening quote lives in the margin.”

Hanging punctuation, the way a typesetter would set it.

In practice

What it looks like in the app.

In the timeline, you see beautifully-rendered posts and probably don't think about why. The em dashes look like em dashes. The quotes are curly. The whitespace is right. You might notice, once, that posts in Lanai look better than the same posts elsewhere. You probably don't notice why.

In settings, there's a section called Typographic touch-ups with three options — All touch-ups (Tiers 0–3), Just display fixes (Tiers 0–2), None (Tier 0 only). Default is All touch-ups.

In a long-press menu on any post, there's Show original. You can verify, copy, or just see.

Bright lines

What we never do.

  • × Modify your post in compose. What you type is what you post.
  • × Modify post records on the network. Cleanup is read-time, not write-time.
  • × Hide that cleanup is happening. Settings explain it; long-press reveals the original.
  • × Claim to “improve” or “fix” posts. We refine display. The post itself is unchanged.
  • × Touch facet content. Mentions, hashtags, links display exactly as the author authored them.
  • × Apply cleanup the user has turned off. The settings toggle is the contract.
  • × Apply Tier 4+ in the timeline. Editorial transformation requires Reading Mode.

For the record

What this is not.

  • Not AI rewriting. No language model touches post text. The cleanup is deterministic, rule-based, and locale-aware.
  • Not autocorrect. We don't change spelling, grammar, or word choice. We change typography, whitespace, and display-layer encoding artifacts.
  • Not "fixing" the author. The author's choices stand. We refine how their choices are rendered, not what they chose.
  • Not opaque. Every transformation is documented, settings-controllable, and reversible.

Read more about how Lanai reads.

Typography is one piece. The intelligence stance and the Postcard Mode argument are the other two.