Skip to content

Commit 01b3c42

Browse files
committed
Make Tigris the default playback origin
1 parent b959b9c commit 01b3c42

36 files changed

Lines changed: 2976 additions & 1402 deletions

.env.docker.example

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,19 @@ REND_AUTUMN_UNIT_COST_STORAGE_720P=
4848
REND_AUTUMN_UNIT_COST_STORAGE_1080P=
4949
REND_AUTUMN_UNIT_COST_STORAGE_2K=
5050
REND_AUTUMN_UNIT_COST_STORAGE_4K=
51+
REND_PLAYBACK_MODE=tigris
52+
REND_TIGRIS_PLAYBACK_BASE_URL=http://127.0.0.1:4000
53+
# Edge playback is dormant by default. Set REND_PLAYBACK_MODE=edge to use these.
5154
REND_PLAYBACK_BASE_URL=http://127.0.0.1:4100
52-
REND_PLAYER_PLAYBACK_BASE_URL=http://localhost:4100
53-
REND_PLAYER_EDGE_BASE_URLS=DEFAULT=http://localhost:4100
55+
REND_PLAYER_PLAYBACK_BASE_URL=
56+
REND_PLAYER_EDGE_BASE_URLS=
5457
REND_PLAYBACK_COOKIE_DOMAIN=
5558
REND_MAX_UPLOAD_BYTES=536870912
56-
# Registry fanout prefers healthy edges registered in rend.edge_nodes.
59+
# Registry fanout is skipped unless REND_PLAYBACK_MODE=edge.
5760
REND_EDGE_ACTIVE_HEARTBEAT_WINDOW_SECS=30
5861
REND_EXPECTED_EDGES=local-edge-001=local=http://rend-edge:4100,rend-edge-us-east=us-east=http://rend-edge-us-east:4100,rend-edge-london=london=http://rend-edge-london:4100
5962
REND_ALLOW_INSECURE_EDGE_URLS=false
60-
# Fallback only when no registered healthy edge is active.
63+
# Fallback only in edge mode when no registered healthy edge is active.
6164
REND_EDGE_WARM_URL=http://rend-edge:4100/internal/warm
6265
REND_EDGE_PURGE_URL=http://rend-edge:4100/internal/purge
6366
REND_INTERNAL_TELEMETRY_TOKEN=dev-internal-token

.env.example

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,16 @@ REND_AUTUMN_UNIT_COST_STORAGE_720P=
5656
REND_AUTUMN_UNIT_COST_STORAGE_1080P=
5757
REND_AUTUMN_UNIT_COST_STORAGE_2K=
5858
REND_AUTUMN_UNIT_COST_STORAGE_4K=
59+
REND_PLAYBACK_MODE=tigris
60+
REND_TIGRIS_PLAYBACK_BASE_URL=http://127.0.0.1:4000
61+
# Edge playback is dormant by default. Set REND_PLAYBACK_MODE=edge to use this base.
5962
REND_PLAYBACK_BASE_URL=http://127.0.0.1:4100
6063
REND_MAX_UPLOAD_BYTES=536870912
61-
# Registry fanout prefers healthy edges registered in rend.edge_nodes.
64+
# Registry fanout is skipped unless REND_PLAYBACK_MODE=edge.
6265
REND_EDGE_ACTIVE_HEARTBEAT_WINDOW_SECS=120
6366
REND_EXPECTED_EDGES=local-edge-001=local=http://127.0.0.1:4100
6467
REND_ALLOW_INSECURE_EDGE_URLS=false
65-
# Fallback only when no registered healthy edge is active.
68+
# Fallback only in edge mode when no registered healthy edge is active.
6669
REND_EDGE_WARM_URL=http://127.0.0.1:4100/internal/warm
6770
REND_EDGE_PURGE_URL=http://127.0.0.1:4100/internal/purge
6871
REND_INTERNAL_TELEMETRY_TOKEN=dev-internal-token

.env.local.example

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ AWS_SECRET_ACCESS_KEY=rend_minio_password
2323

2424
REND_API_BASE_URL=http://127.0.0.1:4000
2525
REND_PUBLIC_API_BASE_URL=http://127.0.0.1:4000
26-
REND_PLAYER_PLAYBACK_BASE_URL=http://localhost:4100
27-
REND_PLAYER_EDGE_BASE_URLS=DEFAULT=http://localhost:4100
26+
REND_PLAYBACK_MODE=tigris
27+
REND_TIGRIS_PLAYBACK_BASE_URL=http://127.0.0.1:4000
28+
# Edge playback is dormant by default. Set REND_PLAYBACK_MODE=edge to use these.
29+
REND_PLAYER_PLAYBACK_BASE_URL=
30+
REND_PLAYER_EDGE_BASE_URLS=
2831
REND_API_CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
2932
REND_API_BIND_ADDR=127.0.0.1:4000
3033
REND_API_AUTO_MIGRATE=true
@@ -66,11 +69,13 @@ REND_AUTUMN_UNIT_COST_STORAGE_720P=
6669
REND_AUTUMN_UNIT_COST_STORAGE_1080P=
6770
REND_AUTUMN_UNIT_COST_STORAGE_2K=
6871
REND_AUTUMN_UNIT_COST_STORAGE_4K=
72+
# Edge playback base used only when REND_PLAYBACK_MODE=edge.
6973
REND_PLAYBACK_BASE_URL=http://127.0.0.1:4100
7074
REND_MAX_UPLOAD_BYTES=536870912
7175
REND_EDGE_ACTIVE_HEARTBEAT_WINDOW_SECS=120
7276
REND_EXPECTED_EDGES=local-edge-001=local=http://127.0.0.1:4100
7377
REND_ALLOW_INSECURE_EDGE_URLS=false
78+
# Edge warm/purge fanout is skipped unless REND_PLAYBACK_MODE=edge.
7479
REND_EDGE_WARM_URL=http://127.0.0.1:4100/internal/warm
7580
REND_EDGE_PURGE_URL=http://127.0.0.1:4100/internal/purge
7681
REND_EDGE_INTERNAL_TOKEN=dev-internal-token

.env.production.example

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ AWS_SECRET_ACCESS_KEY=replace-me
2626
REND_API_BASE_URL=https://api.example.com
2727
REND_PUBLIC_API_BASE_URL=https://api.rend.so
2828
REND_PUBLIC_SITE_BASE_URL=https://rend.so
29-
REND_PLAYER_PLAYBACK_BASE_URL=https://ash-1.play.rend.so
29+
REND_PLAYBACK_MODE=tigris
30+
REND_TIGRIS_PLAYBACK_BASE_URL=https://api.rend.so
31+
# Edge playback is dormant by default. Set REND_PLAYBACK_MODE=edge to use these.
32+
REND_PLAYER_PLAYBACK_BASE_URL=
33+
REND_PLAYER_EDGE_BASE_URLS=
3034
REND_PLAYER_PLAYBACK_COOKIE_DOMAIN=rend.so
3135
REND_API_CORS_ALLOWED_ORIGINS=https://rend.so,https://www.rend.so
3236
REND_API_BIND_ADDR=0.0.0.0:4000
@@ -68,11 +72,13 @@ REND_AUTUMN_UNIT_COST_STORAGE_720P=
6872
REND_AUTUMN_UNIT_COST_STORAGE_1080P=
6973
REND_AUTUMN_UNIT_COST_STORAGE_2K=
7074
REND_AUTUMN_UNIT_COST_STORAGE_4K=
75+
# Edge playback base used only when REND_PLAYBACK_MODE=edge.
7176
REND_PLAYBACK_BASE_URL=https://edge-us-east.example.com
7277
REND_MAX_UPLOAD_BYTES=536870912
7378
REND_EDGE_ACTIVE_HEARTBEAT_WINDOW_SECS=120
7479
REND_EXPECTED_EDGES=rend-edge-us-east-001=us-east=https://edge-us-east.example.com,rend-edge-london-001=london=https://edge-london.example.com
7580
REND_ALLOW_INSECURE_EDGE_URLS=false
81+
# Edge warm/purge fanout is skipped unless REND_PLAYBACK_MODE=edge.
7682
REND_EDGE_WARM_URL=
7783
REND_EDGE_PURGE_URL=
7884
REND_EDGE_INTERNAL_TOKEN=replace-me

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ Rend is the video platform for developers: one API call to upload, one playback
2020
URL that starts fast. Encoding, storage, delivery, signed playback, analytics,
2121
player packages, and SDKs are handled by one open-source stack.
2222

23-
Rend warms the opening bytes of each video onto edge-local RAM and NVMe/SSD,
24-
close to viewers, so playback can start with fewer round trips even on a cold
25-
request. You can run the same stack yourself or use Rend Cloud's managed edge.
23+
Rend currently serves generated HLS from Tigris-backed origin through
24+
Rend-controlled playback URLs, so playback can start without exposing private
25+
storage URLs. The bare-metal edge path remains in the repo, but it is dormant in
26+
production until regional coverage makes it worthwhile.
2627

2728
## Performance Goals
2829

@@ -32,26 +33,25 @@ that has not already been watched and cached everywhere.
3233
- Minimize time to first frame, not just server response time.
3334
- Generate a small opener during media processing so real frames can be served
3435
before the full HLS ladder is ready.
35-
- Warm openers and first playback artifacts to edge nodes before viewers press
36-
play.
37-
- Serve playback from bare-metal edge nodes with local RAM and NVMe/SSD cache,
38-
backed by durable object storage.
39-
- Keep the hot playback path independent of the control plane: signed playback
40-
is validated at the edge before cache lookup, coalescing, or origin fetch.
36+
- Serve generated HLS from Tigris-backed origin by default while the bare-metal
37+
edge path stays dormant until regional coverage makes it worthwhile again.
38+
- Keep playback credentials server-controlled: signed playback is validated
39+
before private origin artifacts are streamed, without exposing storage URLs.
4140
- Measure the path with readiness and benchmark scripts covering upload
42-
response time, upload-to-playable timings, playback bootstrap latency, edge
43-
TTFB for misses/hits/warmed hits, cache behavior, and telemetry visibility.
41+
response time, upload-to-playable timings, playback bootstrap latency,
42+
origin TTFB, optional edge cache behavior, and telemetry visibility.
4443

4544
## Current Shape
4645

4746
- [`apps/site/`](./apps/site) - Next.js app for the public site, docs,
4847
dashboard, auth, billing, and player-facing routes.
4948
- [`services/rend-api/`](./services/rend-api) - Rust API/control plane for
50-
uploads, asset state, media jobs, playback bootstrap, edge registry,
51-
telemetry ingest, and billing hooks.
49+
uploads, asset state, media jobs, playback bootstrap, Tigris-origin playback,
50+
optional edge registry, telemetry ingest, and billing hooks.
5251
- [`services/rend-edge/`](./services/rend-edge) - Rust playback edge for signed
5352
playback validation, cache warm/purge, origin-backed cache fill/coalescing,
54-
and playback telemetry flushing.
53+
and playback telemetry flushing. This code is currently dormant in production
54+
unless `REND_PLAYBACK_MODE=edge` is explicitly enabled.
5555
- `rend-media-worker` - the `rend-api` binary running as `worker media`; claims
5656
queued media jobs and writes playback artifacts with `ffmpeg`/`ffprobe`.
5757
- [`packages/player/`](./packages/player) - React/HLS player package.
@@ -63,7 +63,7 @@ that has not already been watched and cached everywhere.
6363

6464
The local stack currently covers upload, queued media processing, source and
6565
playback artifact storage, HLS/openers/thumbnails, signed playback bootstrap,
66-
edge cache warm/purge/coalescing, playback request analytics, API keys,
66+
Tigris-origin playback, optional edge cache warm/purge/coalescing, API keys,
6767
dashboard asset management, billing checks, and a generated public SDK.
6868

6969
## Requirements

apps/site/app/about/page.tsx

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,18 @@ import { SiteHeader } from "@/components/marketing/SiteHeader";
1010
import { Button } from "@/components/ui/Button";
1111
import { Section } from "@/components/ui/Section";
1212
import { SectionHeading } from "@/components/ui/SectionHeading";
13-
import { GITHUB_URL, getMarketingPage, START_HREF } from "@/lib/marketing-pages";
13+
import {
14+
GITHUB_URL,
15+
getMarketingPage,
16+
START_HREF,
17+
} from "@/lib/marketing-pages";
1418
import { pageMetadata } from "@/lib/seo";
15-
import { breadcrumbLd, faqLd, organizationLd, webPageLd } from "@/lib/structured-data";
19+
import {
20+
breadcrumbLd,
21+
faqLd,
22+
organizationLd,
23+
webPageLd,
24+
} from "@/lib/structured-data";
1625

1726
const page = getMarketingPage("/about");
1827

@@ -33,7 +42,12 @@ export default function AboutPage() {
3342
<Effects />
3443
<JsonLd
3544
data={[
36-
webPageLd({ name: page.title, description: page.description, path: page.path, type: "AboutPage" }),
45+
webPageLd({
46+
name: page.title,
47+
description: page.description,
48+
path: page.path,
49+
type: "AboutPage",
50+
}),
3751
breadcrumbLd(breadcrumbs),
3852
faqLd(page.faqs),
3953
organizationLd(),
@@ -46,17 +60,30 @@ export default function AboutPage() {
4660
title="We couldn't buy fast video, so we built it"
4761
lede={
4862
<p>
49-
Rend started as plumbing for Cap, our open source screen recorder. The story is short. We
50-
needed video that played the instant someone opened a link, nothing on the market did it
51-
the way we wanted, and so we wrote our own.
63+
Rend started as plumbing for Cap, our open source screen recorder.
64+
The story is short. We needed video that played the instant
65+
someone opened a link, nothing on the market did it the way we
66+
wanted, and so we wrote our own.
5267
</p>
5368
}
5469
actions={
5570
<>
56-
<Button href="https://cap.so" external size="lg" variant="secondary" className="w-full sm:w-auto">
71+
<Button
72+
href="https://cap.so"
73+
external
74+
size="lg"
75+
variant="secondary"
76+
className="w-full sm:w-auto"
77+
>
5778
Visit Cap
5879
</Button>
59-
<Button href={GITHUB_URL} external size="lg" variant="secondary" className="w-full sm:w-auto">
80+
<Button
81+
href={GITHUB_URL}
82+
external
83+
size="lg"
84+
variant="secondary"
85+
className="w-full sm:w-auto"
86+
>
6087
<GitHubMark />
6188
Star on GitHub
6289
</Button>
@@ -69,34 +96,41 @@ export default function AboutPage() {
6996
<SectionHeading title="The video we kept losing" />
7097
<div className="mt-8 flex max-w-[660px] flex-col gap-5 text-[17px] leading-[1.7] text-ink-soft">
7198
<p>
72-
Cap is a screen recorder. You hit record, capture something on your screen, and send a
73-
link. The whole thing rests on one moment: a teammate clicks that link, and the video is
74-
already playing. If it stalls, the moment is gone and so is their attention.
99+
Cap is a screen recorder. You hit record, capture something on
100+
your screen, and send a link. The whole thing rests on one moment:
101+
a teammate clicks that link, and the video is already playing. If
102+
it stalls, the moment is gone and so is their attention.
75103
</p>
76104
<p>
77-
For a while we stitched that moment together from the usual parts, and it mostly held up.
78-
The slow case was always the same one: the very first time anyone opened a clip. Nothing
79-
was cached, the bytes were sitting in some distant bucket, and the player just spun while
80-
the round trips stacked up. That first frame is the one that matters most, and it was the
81-
one we kept losing.
105+
For a while we stitched that moment together from the usual parts,
106+
and it mostly held up. The slow case was always the same one: the
107+
very first time anyone opened a clip. Nothing was cached, the
108+
bytes were sitting in some distant bucket, and the player just
109+
spun while the round trips stacked up. That first frame is the one
110+
that matters most, and it was the one we kept losing.
82111
</p>
83112
<p>
84-
So we went shopping. Minute-billed platforms, per-gigabyte CDNs, the lot. They were good
85-
at the easy case, a video that has already been watched a thousand times and cached
86-
everywhere. None of them were built for the cold open, the first request to a brand new
113+
So we went shopping. Minute-billed platforms, per-gigabyte CDNs,
114+
the lot. They were good at the easy case, a video that has already
115+
been watched a thousand times and cached everywhere. None of them
116+
were built for the cold open, the first request to a brand new
87117
recording, which for a screen recorder is most of the traffic.
88118
</p>
89119
<p>
90-
In the end we built it ourselves. Rend warms the opening seconds of every video onto
91-
hardware sitting close to the viewer, before anyone presses play. The first request hands
92-
back real frames while the rest streams in behind it. The cold case stopped being the slow
93-
case, and Cap started feeling instant.
120+
In the end we built it ourselves. Rend generates the playback
121+
artifacts players need during processing and serves them through
122+
Rend-controlled URLs. The first request can hand back real HLS
123+
media without exposing private storage links, and Cap started
124+
feeling instant.
94125
</p>
95126
<p>
96-
Then it occurred to us that every developer shipping video runs into the same wall, so we
97-
opened it up. Rend is its own product now, running on the exact code that serves Cap.
127+
Then it occurred to us that every developer shipping video runs
128+
into the same wall, so we opened it up. Rend is its own product
129+
now, running on the exact code that serves Cap.
130+
</p>
131+
<p className="font-head text-[26px] leading-snug text-ink">
132+
Cap runs entirely on Rend.
98133
</p>
99-
<p className="font-head text-[26px] leading-snug text-ink">Cap runs entirely on Rend.</p>
100134
</div>
101135
</Section>
102136

@@ -107,9 +141,10 @@ export default function AboutPage() {
107141
lede="We did not keep a faster version for ourselves. Rend is open source, and the code you self-host is what we run for Cap."
108142
/>
109143
<p className="mt-5 max-w-[640px] text-[17px] leading-[1.6] text-muted">
110-
The server is AGPL and the player and SDKs are MIT. You can read every line, run it on your
111-
own machines for free, or let us run the edge for you. We do not charge for the software. We
112-
charge for the network that makes it fast.
144+
The server is AGPL and the player and SDKs are MIT. You can read
145+
every line, run it on your own machines for free, or let us run the
146+
edge for you. We do not charge for the software. We charge for the
147+
network that makes it fast.
113148
</p>
114149
<div className="mt-8 flex flex-wrap items-center gap-x-6 gap-y-3">
115150
<Button href={GITHUB_URL} external variant="secondary" size="md">
@@ -128,20 +163,31 @@ export default function AboutPage() {
128163
{/* The team */}
129164
<Section tone="sunken" aria-label="The team behind Rend">
130165
<img src="/cap-logo.svg" alt="Cap" className="h-8 w-auto" />
131-
<h2 className="mt-6 text-[clamp(26px,5vw,40px)] leading-[1.12]">A small team that hates buffering</h2>
166+
<h2 className="mt-6 text-[clamp(26px,5vw,40px)] leading-[1.12]">
167+
A small team that hates buffering
168+
</h2>
132169
<p className="mt-5 max-w-[640px] text-[17px] leading-[1.6] text-muted">
133-
We are the team behind Cap. We care, maybe a little too much, about video that loads the
134-
second you ask for it. Rend is the infrastructure we built to get there, and we run it in
135-
the open so you can hold us to it.
170+
We are the team behind Cap. We care, maybe a little too much, about
171+
video that loads the second you ask for it. Rend is the
172+
infrastructure we built to get there, and we run it in the open so
173+
you can hold us to it.
136174
</p>
137175
<div className="mt-8">
138-
<Button href="https://cap.so" external variant="secondary" size="md">
176+
<Button
177+
href="https://cap.so"
178+
external
179+
variant="secondary"
180+
size="md"
181+
>
139182
Visit Cap
140183
</Button>
141184
</div>
142185
</Section>
143186

144-
<Faq faqs={page.faqs} lede="A few questions we get about who is behind Rend." />
187+
<Faq
188+
faqs={page.faqs}
189+
lede="A few questions we get about who is behind Rend."
190+
/>
145191

146192
<CtaSection
147193
title="Build on the infrastructure that runs Cap"

0 commit comments

Comments
 (0)