diff --git a/76.md b/76.md new file mode 100644 index 0000000000..9391dc7adc --- /dev/null +++ b/76.md @@ -0,0 +1,203 @@ +NIP-76 +====== + +Reels Feed — Short-form Video Discovery and Interaction +------------------------------------------------------- + +`draft` `optional` + +This NIP builds on top of [NIP-71](71.md) to define a standard for **short-form vertical video feeds** (commonly known as "Reels", "Shorts", or "Stories") including feed curation, loop-play behavior, duet/stitch interactions, and client rendering expectations. + +NIP-71 defines the event kinds for short videos (`kind:22` and `kind:34236`). This NIP defines the **social layer** on top of those events: how clients discover, surface, rank, and let users interact with short-form content in an infinite-scroll feed experience. + +--- + +## Feed Discovery + +Clients wishing to render a Reels-style feed SHOULD subscribe to `kind:22` and `kind:34236` events with the following relay filter: + +```json +{ + "kinds": [22, 34236], + "limit": 50 +} +``` + +To build a personalized feed, clients SHOULD use the user's follow list (NIP-02) to scope the subscription: + +```json +{ + "kinds": [22, 34236], + "authors": ["", "..."], + "limit": 50 +} +``` + +Clients MAY additionally use hashtag filters via `#t` to build topic-specific feeds. + +--- + +## Client Rendering Requirements + +Clients implementing a Reels feed MUST: + +- Display videos in a **vertical (portrait) layout** — the recommended aspect ratio is **9:16** +- **Autoplay muted** when the video enters the viewport +- **Loop** the video until the user scrolls away or explicitly stops it +- Provide a visible control to **unmute/mute** audio +- Render the event's `content` field as a caption overlay or below the video + +Clients SHOULD: +- Preload the next video in the feed for smooth scrolling +- Display `t` tags as tappable hashtag links +- Show the author's avatar and display name (NIP-01 metadata) overlaid on or beside the video + +--- + +## Duet / Stitch Interaction (Reply Videos) + +A user may respond to a short video with their own short video — a "duet" or "stitch". This is expressed as a standard NIP-10 reply from a `kind:22` or `kind:34236` event pointing to the original video event. + +### Duet Event + +A **duet** plays both the original and the response video side-by-side simultaneously. + +```json +{ + "kind": 22, + "content": "My duet with this! #duet", + "tags": [ + ["e", "", "", "reply"], + ["p", ""], + ["t", "duet"], + ["title", "Duet with @originalauthor"], + ["imeta", + "url https://example.com/my-duet-video.mp4", + "m video/mp4", + "dim 540x1920", + "image https://example.com/my-duet-thumb.jpg", + "duration 28.0" + ] + ] +} +``` + +### Stitch Event + +A **stitch** plays a clip of the original first, then cuts to the response video sequentially. + +```json +{ + "kind": 22, + "content": "Replying to this point! #stitch", + "tags": [ + ["e", "", "", "reply"], + ["p", ""], + ["t", "stitch"], + ["stitch-start", "00:00:03.000"], + ["stitch-end", "00:00:08.000"], + ["title", "Stitch: responding to @originalauthor"], + ["imeta", + "url https://example.com/my-stitch-response.mp4", + "m video/mp4", + "dim 1080x1920", + "image https://example.com/stitch-thumb.jpg", + "duration 45.0" + ] + ] +} +``` + +| Tag | Description | +|-----|-------------| +| `stitch-start` | Timestamp (`HH:MM:SS.sss`) in the **original** video where the clip begins | +| `stitch-end` | Timestamp (`HH:MM:SS.sss`) in the **original** video where the clip ends | + +Clients rendering a stitch SHOULD fetch the original event via the `e` tag and play the clipped segment before playing the response video. + +--- + +## Reels Curation List + +A user may publish a curated list of short videos as a "Reels Collection" using `kind:30076` (a parameterized replaceable event). + +```json +{ + "kind": 30076, + "content": "My favourite cooking reels", + "tags": [ + ["d", "cooking-reels"], + ["title", "Cooking Reels"], + ["description", "Short cooking videos I love"], + ["e", "", ""], + ["e", "", ""], + ["a", "34236::", ""], + ["t", "cooking"], + ["t", "food"] + ] +} +``` + +Clients MAY surface these lists as shareable channels or playlists in their feed UI. + +--- + +## Interaction Events + +All standard Nostr interaction NIPs apply to short video events: + +| Interaction | NIP | Notes | +|-------------|-----|-------| +| Reactions (likes) | [NIP-25](25.md) | `+`, `-`, or emoji | +| Zaps | [NIP-57](57.md) | Lightning payments | +| Comments | [NIP-10](10.md) | Text replies via `kind:1` | +| Reposts | [NIP-18](18.md) | `kind:6` repost | +| Bookmarks | [NIP-51](51.md) | Save to private/public list | +| Video replies | This NIP | Duet / Stitch via `kind:22` | + +--- + +## Relay Recommendations + +Relays that wish to optimize for short-form video content SHOULD: + +- Index `kind:22` and `kind:34236` events separately from `kind:1` text notes +- Support `NIP-50` full-text search over video `title` and `content` fields +- Expose a dedicated feed endpoint via `NIP-11` relay info, e.g.: + +```json +{ + "supported_nips": [76], + "reels_feed": true +} +``` + +--- + +## Summary of New Event Kinds and Tags + +| Kind | Description | +|------|-------------| +| `22` | Short video (NIP-71, used here for duet/stitch) | +| `34236` | Addressable short video (NIP-71) | +| `30076` | Reels curation collection (this NIP) | + +| Tag | Event | Description | +|-----|-------|-------------| +| `t duet` | `kind:22` reply | Marks a video reply as a side-by-side duet | +| `t stitch` | `kind:22` reply | Marks a video reply as a sequential stitch | +| `stitch-start` | `kind:22` reply | Start timestamp for the stitched clip | +| `stitch-end` | `kind:22` reply | End timestamp for the stitched clip | + +--- + +## Relation to Other NIPs + +- **NIP-71** — defines `kind:22` and `kind:34236` short video events; this NIP extends them +- **NIP-92** — `imeta` tag used for video metadata +- **NIP-94** — file metadata used within `imeta` +- **NIP-96** — decentralized file storage for video uploads +- **NIP-10** — reply threading for duet/stitch events +- **NIP-25** — reactions +- **NIP-57** — zaps +- **NIP-51** — bookmark/curation lists diff --git a/README.md b/README.md index a3e37e99cd..8e91d53b91 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ NIPs listed here are not a protocol checklist. Nothing forces any software to im - ~~[NIP-72: Moderated Communities](72.md) --- **unrecommended**: try [NIP-29](29.md) instead~~ - [NIP-73: External Content IDs](73.md) - [NIP-75: Zap Goals](75.md) +- [NIP-76: Reels Feed — Short-form Video Discovery and Interaction](76.md) - [NIP-77: Negentropy Syncing](77.md) - [NIP-78: Application-specific data](78.md) - [NIP-7D: Forum Threads](7D.md)