[docs] Refine shorts/live plans: portrait card design + committed VOD & chat phases

Shorts (docs/shorts-plan.md):
- Add DECISION 6 + architecture/phase items for a NEW portrait 9:16 card design.
  The existing VideoCard.js is hardcoded 16:9 (ratio-16-9), so shorts need either
  a "short" variant of VideoCard or a dedicated ShortCard — a first-class Phase 1
  deliverable, not an afterthought.

Live ingest (docs/live-ingest-plan.md):
- Reframe past streams (VOD) and chat from "deferred/maybe" to committed phases:
  Phase 3 read-only chat (+ optional 3b post), Phase 4 ended/recording VOD
  playback through the same HLS path. So the plan's phases fully account for
  live AND past zap.stream streams AND chat.
- Add a distinct LiveCard design (LIVE badge, viewer count, ended state).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-07-01 11:15:01 -04:00
1 parent 163f7e11d5
commit 8e76f0d7a8
2 files changed
+50 -16

No files matched your search

+25 -12
View File
@@ -24,10 +24,12 @@ a config flag that leaves **no trace** when off.
> *Recommendation: whitelisted hosts for v1 — consistent with the rest of bitvid's
> trust model and avoids surfacing arbitrary/abusive streams.*
> **DECISION 2 — Live chat in v1?** Read-only kind-1311 chat alongside the player,
> or playback-only for v1 (chat later)?
> *Recommendation: playback-only v1; add read-only chat in a later phase. Chat is
> a live subscription with its own moderation questions.*
> **DECISION 2 — Chat level (read-only vs read + post).** Chat is **committed to
> the roadmap** (Phase 3), the only open question is how far: **read-only** (kind
> 1311 ingest — stays cleanly inside "ingest"), or **read + post** (signing/
> publishing 1311 events — a write path, likely its own sub-flag + moderation
> stance). *Recommendation: read-only in Phase 3, then read + post as Phase 3b if
> wanted. Playback (Phases 1–2) ships before chat regardless.*
> **DECISION 3 — HLS playback dependency.** OK to lazy-load a small HLS library
> (**hls.js**, ~cdn/vendored) ONLY when the flag is on, or must playback stay
@@ -35,10 +37,13 @@ a config flag that leaves **no trace** when off.
> *Recommendation: allow hls.js, lazy-imported behind the flag (native HLS alone
> won't play `.m3u8` in Chrome/Firefox). It never loads when the flag is off.*
> **DECISION 4 — Ended streams / VOD.** When `status=ended`, some events carry a
> `recording` URL (a VOD). Show ended streams with playback of the recording,
> hide them, or list-but-mark-ended? *Recommendation: v1 shows only `status=live`;
> treat recordings as a later enhancement.*
> **DECISION 4 — Past streams / VOD presentation.** Past (ended) streams are
> **committed to the roadmap** (Phase 4): a `status=ended` event carries a
> `recording` URL (a VOD, usually `.m3u8`/mp4) which plays through the same HLS
> path as live. Open question is only *presentation*: mix ended streams into the
> Live tab (marked "ended"), or give them a separate "Past streams" section/sort?
> *Recommendation: one Live tab that lists live first, then recent ended streams
> marked accordingly; a dedicated section only if it gets crowded.*
> **DECISION 5 — Discovery relays.** Use the user's normal read relays, or add
> stream-heavy relays (zap.stream's relay etc.) for discovery? *Recommendation:
@@ -102,6 +107,10 @@ chat message. Read-only ingest = subscribe by `#a`, render newest.
`nip71IngestService` so it stays off the cold-start critical path.
- **Sidebar tab + view:** "Live" link in `components/sidebar.html` (flag-gated) +
`views/live.html` (grid of live cards).
- **Card design (new):** a **live card** distinct from `VideoCard.js` — a **LIVE
badge**, viewer count, host name/avatar, and an "ended" state for past streams
(Phase 4). Likely a dedicated `LiveCard` (the live/ended metadata differs enough
from a video card that a variant is awkward). New `data-testid` for e2e.
- **Player:** a live player path. The current player
(`js/services/playbackService.js`) sets `videoEl.src` for URL/WebTorrent; HLS
needs hls.js attached to the `<video>` element when the source is `.m3u8`
@@ -126,10 +135,14 @@ chat message. Read-only ingest = subscribe by `#a`, render newest.
live cards, route gated by flag. Clicking a card opens… (Phase 2).
- **Phase 2 — HLS playback (medium).** Live player path + lazy hls.js; play the
`streaming` URL; graceful error when the stream is down.
- **Phase 3 — Read-only chat (medium, DECISION 2).** kind-1311 subscription +
render + teardown.
- **Phase 4 — Polish.** Viewer counts, ended/recording handling (DECISION 4),
optional extra discovery relays (DECISION 5), poster/skeleton states.
- **Phase 3 — Chat (medium, DECISION 2).** Read-only kind-1311 subscription by
`#a` + render + teardown. Optional **Phase 3b — post chat** (sign/publish 1311,
its own sub-flag + moderation stance) if read+post is chosen.
- **Phase 4 — Past streams / VOD (medium, DECISION 4).** List `status=ended`
events and play their `recording` URL through the same HLS player; mark ended
vs live in the UI. This is the "past zap.stream streams" capability.
- **Phase 5 — Polish.** Viewer counts, optional extra discovery relays
(DECISION 5), poster/skeleton states, liveness de-emphasis for stale events.
---
+25 -4
View File
@@ -46,6 +46,19 @@ source that lists only shorts. Everything ships behind a config flag that leaves
> *Recommendation: ship the grid + portrait player first (small), then layer the
> swipe feed as a phase 2 — keeps the first release cheap.*
> **DECISION 6 — Card design.** Shorts need a **new portrait (9:16) card** — the
> existing `js/ui/components/VideoCard.js` hardcodes a **16:9 landscape** media
> ratio (`ratio-16-9`), so it can't render shorts correctly as-is. Two options:
> (a) a **new `ShortCard` component** (portrait thumbnail, compact meta, its own
> `data-testid`); or (b) a **portrait "mode"/variant of `VideoCard`** driven by a
> flag (e.g. `variant: "short"` swapping the ratio class + layout).
> *Recommendation: (b) a portrait variant of `VideoCard` if the internals are
> clean enough to parameterize the ratio + layout — it inherits thumbnail
> binding, moderation badges, engagement controls, and the ⋯ menu for free;
> fall back to (a) a dedicated `ShortCard` only if forcing a variant makes
> `VideoCard` unwieldy or pushes it past its size cap.* Either way this is a
> **first-class deliverable**, not an afterthought — the grid can't ship without it.
---
## Config flag (off = no trace)
@@ -97,6 +110,12 @@ Reuses the existing feed engine + ingest; new pieces are thin.
- **Sidebar tab:** add a Shorts link in `components/sidebar.html`, rendered only
when the flag is on.
- **View:** `views/shorts.html` (a portrait-oriented grid container).
- **Card design (new):** a portrait **9:16** card — either a `variant: "short"`
mode of `js/ui/components/VideoCard.js` (which is currently 16:9 / `ratio-16-9`)
or a dedicated `ShortCard` (DECISION 6). Portrait thumbnail, compact title +
author, reuse of thumbnail binding, moderation badges, engagement + ⋯ menu. New
design tokens if needed (existing `--video-card-*` tokens live in
`css/tokens.css`). A distinct `data-testid` for e2e selectors.
- **Player UI:** v1 opens a short in the existing player modal with a portrait
layout; v2 adds a full-screen vertical swipe/next feed.
- **Diversity:** apply the existing `spreadAuthors` pass (feed sorters) so the
@@ -108,10 +127,12 @@ Reuses the existing feed engine + ingest; new pieces are thin.
- **Phase 0 — Detection + flag (small).** Add `FEATURE_SHORTS` (off), `isShort`
derivation in the ingest adapter + mirror, unit tests for detection. No UI.
- **Phase 1 — Tab + feed (small–medium).** `FEED_TYPES.SHORTS`, sidebar link,
`views/shorts.html`, feed registration filtered to `isShort`, route gated by
flag. Grid renders; opens in the standard player.
- **Phase 2 — Vertical UX (medium).** Portrait player layout + swipe/next feel.
- **Phase 1 — Tab + feed + portrait card (medium).** `FEED_TYPES.SHORTS`, sidebar
link, `views/shorts.html`, feed registration filtered to `isShort`, route gated
by flag, and the **new portrait 9:16 card** (DECISION 6) so the grid renders
shorts correctly. Opens in the standard player for now.
- **Phase 2 — Vertical UX (medium).** Portrait player layout + full-screen
swipe/next feed.
- **Phase 3 — Polish.** Autoplay-on-scroll, mute toggle, per-tab empty states,
optional exclusion from the main feed (DECISION 3 revisit).