# Ohiyo UX Gates โ€” world-class messaging checklist The bar for a messaging app people *love* isn't features โ€” it's feel. These are the gates, scored honestly against the current build. **Legend:** โœ… meets the bar ยท ๐ŸŸก partial / good-on-desktop ยท โŒ not built yet. | # | Gate | Status | Where we stand | |---|------|--------|----------------| | 1 | **Send feels instant** (<100 ms local) | โœ… | Optimistic `temp-` messages render immediately on send and reconcile on the gateway echo. Effectively instant. | | 2 | **Input never janks** | ๐ŸŸก | Composer is a plain controlled input โ€” no jank on desktop. No soft-keyboard coordination needed until mobile. | | 3 | **Scroll never betrays** | โœ… | **Fixed.** Auto-scrolls to the latest only when you're already at the bottom (or on your own send / channel switch). Read history undisturbed; a new message surfaces a **"โ†“ New messages"** pill instead of yanking. (Two-user verified: no jump + pill.) History-prepend anchoring N/A until infinite-scroll-up exists. | | 4 | **Every message has a clear state** | โœ… | **Fixed.** Optimistic message renders **dimmed (pending)** โ†’ **sent** on echo, or **failed** with an inline **Retry / Delete** affordance if the send errors (no silent vanish). e2e-locked (`14-failed-retry`). Read receipts now ship (e2e-locked, `17-receipts`). | | 5 | **Media never causes layout shift** | โœ… | **Fixed.** Server records image pixel dimensions at upload (`imagesize`); the client reserves the exact aspect-ratio frame with a soft placeholder before the image loads, and `estimateHeight` uses real dimensions (also kills the last scroll-jump source). Also fixed a latent bug: attachments were never parsed (returned as a JSON string), so images never actually rendered. e2e-locked (`15-images`). ThumbHash blur-up is an optional future nicety. | | 6 | **Composer is sacred** | ๐ŸŸก (improved) | **Per-channel text drafts now ship** (e2e-tested: no leak, restored on return), and cursor is preserved. Still TODO: per-channel **attachments + reply target** (reply is currently just cleared on switch). | | 7 | **Offline-first queue** | โœ… | **Fixed.** Unsent messages persist to a localStorage **outbox** (`lib/outbox.ts`), survive channel switches and reloads (merged back per channel), and **auto-flush** when connectivity returns (browser `online` event + gateway reconnect). e2e-locked (`16-outbox`). Caveat: no server idempotency key yet, so a send the server accepted but whose response was lost can re-send once on flush. | | 8 | **Presence is smoothed** | ๐ŸŸก | Typing is debounced server-side (2.5 s cooldown) + client TTL (5 s) โ€” not flickery. Online/offline via gateway. Read receipts now ship (e2e-locked, `17-receipts`). | | 9 | **Touch has physics** | โŒ (deferred) | Swipe-to-reply / long-press / spring / haptics are **mobile** concerns. Current target is the Tauri desktop app; revisit when a mobile build lands. | | 10 | **Low-end hardware is first-class** | ๐ŸŸก | Lightweight by construction (small bundle, Rust backend, virtualized message list, CSS motion with `prefers-reduced-motion`). Not yet profiled on low-end devices. | ## Recently shipped - **Message list redesign** โ€” persistent per-message action rows โ†’ Discord-style **floating hover toolbar**; tight author-grouping; reactions only when present; **hover-gutter timestamps**. - **Server-rail hover** (squircle + accent tint) to match the existing active-pill indicator. - **Gate 6: per-channel drafts** (composer is sacred) โ€” e2e-locked (`13-drafts`). - **Gate 3: scroll anchoring** โ€” near-bottom auto-follow + "โ†“ New messages" pill (two-user verified). - **Gate 4: message state machine** โ€” pending (dimmed) โ†’ sent / failed + Retry โ€” e2e-locked (`14-failed-retry`). ## Scorecard now โœ… **1, 3, 4, 5, 6, 7** ยท ๐ŸŸก **2, 8, 10** (good on desktop) ยท โŒ/deferred **9** (mobile). ## Priority order for the next passes 1. **Gate 9 โ€” Touch physics** (DEFERRED). With the mobile build (swipe-to-reply, long-press, springs, haptics). 2. **Polish remainders.** Header + composer icon restyle; broader hover/active audit (modals, voice overlay). 3. **Hardening nice-to-haves.** ThumbHash blur-up (gate 5), server idempotency key so outbox flush can never duplicate (gate 7), per-channel attachments/reply (gate 6). ## Visual polish still open (from the earlier diagnosis) - Header + composer icon refinement (#4 of the visual list) โ€” functional, not yet restyled. - Broader hover/active-state audit across modals and the voice overlay.