Divine is 6-second, human-made video on Nostr — no AI slop. This repo is the web client that powers divine.video: a React 18 + TypeScript single-page app, built with Vite, that reads and writes short-form looping videos as Nostr events and renders them in feeds, profiles, and embeds. It ships as a static bundle served from a Fastly Compute edge worker, with a Cloudflare Pages backup.
- 6-second looping videos as Nostr kind
34236(NIP-71 addressable short video), with MP4 and HLS playback and Blurhash placeholders for progressive loading. - Feeds: Home (following), Discovery, Trending/Popular, Hashtag, Categories, and per-user Profile feeds.
- Search using NIP-50 full-text search against
relay.divine.video, including relay-side sort modes (sort:hot,sort:top,sort:rising,sort:controversial). Non-NIP-50 relays fall back to chronological results. - Social: likes, reposts, follows, comments/conversations, notifications, direct messages, lists, and leaderboards.
- Subdomain profiles:
alice.divine.videoresolves a user's Nostr profile via NIP-05 and renders their feed. - Legacy Vine archive pages for preserving and browsing classic Vine content.
- Trust & safety: content moderation settings, age review, and protected-minor safeguards (locked adult-content settings, restricted DMs).
- Video upload to Blossom media servers with a metadata form.
- Internationalization across 20 locales (
ar de en es fil fr id it ja ko ms nl pl pt ro sv tr ur vi zh). - Installable PWA with an offline service worker (apex domain only).
- Server-rendered embeds and social previews: the edge worker injects Open Graph tags and serves embed pages so shared links unfurl correctly for crawlers.
The app is a client-side SPA. The entry flow is index.html → src/main.tsx → src/App.tsx → src/AppRouter.tsx; routing uses react-router-dom v6. Server state comes from @tanstack/react-query via @nostrify/react, which handles Nostr queries, mutations, and subscriptions. Cross-component state flows through React contexts. Styling is TailwindCSS with Radix UI primitives wrapped in src/components/ui/ (shadcn/ui conventions).
See ARCHITECTURE.md for the full module layout, state model, and relay-routing details.
How it fits the Divine platform:
- Nostr is the data layer. The primary relay is
wss://relay.divine.video; relay routing (src/lib/relayRouting.ts) splits reads and writes across profile, badge, and general relay sets. Relay configuration lives insrc/config/relays.ts. - Auth uses
@divinevideo/loginwith a Keycast remote signer, hydrated from cross-subdomain cookies so a session is shared across*.divine.video. - Blossom media servers store and serve uploaded video and images; playback also pulls from
cdn.divine.video. - Funnelcake is the Divine REST API (
api.divine.video, staging atapi.staging.divine.video), used alongside the relay for feeds and video metadata. Configured insrc/config/api.ts. - Moderation is backed by
moderation-api.divine.video. - Edge worker (
compute-js/) is a Fastly Compute JavaScript app that handles crawler requests, Open Graph tags, embed pages,.well-knownapp-link files, and host redirects, proxying to the funnelcake backend for video metadata.
Requires Node.js 20 (see .node-version) and npm.
npm run dev # start the Vite dev server on http://localhost:8080
npm run build # production build to dist/ (+ 404.html, .well-known, prerendered legal pages)
npm run preview # preview the production build
npm test # type-check, lint, unit tests (Vitest), then build — the CI gateVisual regression tests run under Playwright:
npm run test:visual # run snapshot tests
npm run test:visual:update # update snapshotsCopy .env.example to .env. Environment variables (all optional):
VITE_SENTRY_DSN— Sentry DSN for error tracking.VITE_SENTRY_DEV_ENABLED— set totrueto enable Sentry in development (disabled by default).
Relay endpoints are defined in src/config/relays.ts and API base URLs in src/config/api.ts.
Pushing to main triggers the Deploy to Production GitHub Actions workflow (.github/workflows/deploy.yml), which builds the bundle once and then deploys it to two targets:
- Fastly Compute (primary) — publishes the edge worker from
compute-js/, uploads the static bundle to the Fastly KV store, purges the cache, and verifies that the live.well-knownendpoints and frontend bundle match the build before finishing. - Cloudflare Pages (backup) — deploys
dist/to thedivine-web-direct-deployproject via Wrangler.
A failed deploy probes the live apex and alerts #divine-alerts. To run the Fastly worker locally:
npm run fastly:local # build, then start the local Fastly Compute serverDEPLOYMENT.md documents the Cloudflare Pages backup path in more detail.
Part of Divine — your playground for human creativity · Brand guidelines