-
Notifications
You must be signed in to change notification settings - Fork 7
Announcement cards for open-source features #147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ node_modules/ | |
|
|
||
| # Build output | ||
| dist/ | ||
| tools/cards/out/ | ||
| .astro/ | ||
| tsconfig.tsbuildinfo | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Announcement cards | ||
|
|
||
| Social cards for new open-source features, in the style Bun uses for its "in | ||
| the next version" posts: one headline, one code block, 1200x675, posted as an | ||
| image with a one-line caption. CDN announcements live in moq.pro's copy of this | ||
| tool, which shares the look. | ||
|
|
||
| | file | what it is | | ||
| | --- | --- | | ||
| | `cards.ts` | The cards. Add one entry per post; the comment at the top documents the fields and the inline markup. | | ||
| | `render.ts` | Renders each card to `out/<slug>.png` with the devshell's Playwright Chromium. Fails on a card whose content overflows rather than cropping it. | | ||
| | `underline.svg`, `jetbrains-mono-latin.woff2` | The hand-drawn underline and code font, copied from moq.pro's splash page. The wordmark is `public/home/logo.svg`. | | ||
|
|
||
| ```sh | ||
| just cards # every card | ||
| just cards e2ee # one or more slugs | ||
| just cards --html # also write out/<slug>.html, to tweak the layout in a browser | ||
| ``` | ||
|
|
||
| Change the look in `render.ts`, not per card. | ||
|
|
||
| `out/` is ignored. A card is retired from `cards.ts` once posted; the git | ||
| history keeps it. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| // The announcement cards for the open-source stack (crates + npm packages), one | ||
| // entry per post. `just cards` turns each into a 1200x675 PNG for | ||
| // X/Bluesky/Discord (the format Bun uses for its "in the next version" posts). | ||
| // CDN announcements live in moq.pro's copy of this tool. Copy conventions: | ||
| // | ||
| // - `title` is the headline. `**word**` gets the hand-drawn green underline | ||
| // from the splash, so save it for the one phrase the post is about. | ||
| // - `sub` accepts `` `mono` `` and `**green**`. `code` is syntax-highlighted as | ||
| // `lang` (shell by default), where a line starting with `$ ` is a prompt. | ||
| // - `eyebrow` (top right) names the release: a crate + version. `note` (bottom right) is the one-line kicker, if any. | ||
| // | ||
| // Keep cards factual: a version, a rate, a measured number. Retire a card once | ||
| // it has been posted; the git history is the archive. | ||
|
|
||
| export type Lang = "shell" | "rust" | "toml" | "ts"; | ||
|
|
||
| export type Card = { | ||
| slug: string; | ||
| eyebrow?: string; | ||
| title: string; | ||
| sub?: string; | ||
| code?: string; | ||
| lang?: Lang; | ||
| note?: string; | ||
| }; | ||
|
|
||
| export const CARDS: Card[] = [ | ||
| { | ||
| slug: "e2ee", | ||
| eyebrow: "new crate: moq-e2ee 0.0.1", | ||
| title: "End-to-end **encrypted** media.", | ||
| sub: "Relays forward ciphertext. Content keys never enter `moq-net`. AES-128-GCM inline: about 1.3 µs per 1 KiB frame, 440 ns per Opus datagram.", | ||
| code: "$ cargo add moq-e2ee", | ||
| note: "draft-lcurley-moq-e2ee, profile moq-e2ee-01", | ||
| }, | ||
| { | ||
| slug: "uring", | ||
| eyebrow: "new crate: moq-uring 0.0.1", | ||
| title: "io_uring, **thread per core**.", | ||
| sub: "One ring per worker: multishot `recvmsg` from a provided-buffer ring, `UDP_GRO` in, `UDP_SEGMENT` out, timers on the ring, futex parking. QUIC on top, no tokio in the hot path.", | ||
| code: [ | ||
| "[runtime]", | ||
| "workers = 8 # one QUIC worker per core, SO_REUSEPORT steered by connection id", | ||
| "pin = true", | ||
| "io_uring = true # Linux 6.12+; older kernels keep the tokio stack", | ||
| ].join("\n"), | ||
| lang: "toml", | ||
| note: "moq-relay 0.15", | ||
| }, | ||
| { | ||
| slug: "noq", | ||
| eyebrow: "moq-tokio 0.19", | ||
| title: "**noq** is the default QUIC stack.", | ||
| sub: "Every native MoQ binary now dials with our own QUIC implementation. quinn and quiche stay one feature flag away.", | ||
| code: [ | ||
| "[dependencies]", | ||
| 'moq-tokio = "0.19" # noq', | ||
| 'moq-tokio = { version = "0.19", features = ["quinn"] }', | ||
| 'moq-tokio = { version = "0.19", features = ["quiche"] }', | ||
| ].join("\n"), | ||
| lang: "toml", | ||
| }, | ||
| { | ||
| slug: "binary", | ||
| eyebrow: "new crate: moq-binary 0.1.0", | ||
| title: "Binary tracks: **snapshot** or **stream**.", | ||
| sub: "`snapshot` is lossy: one value over time, consumers get the latest. `stream` is lossless: an ordered append-log, nothing superseded. Same DEFLATE framing as `moq-json`, so the two agree on the wire.", | ||
| code: [ | ||
| "// a poster image: whoever joins late gets the current one", | ||
| "let poster = snapshot::Producer::new(track, snapshot::ProducerConfig::default());", | ||
| "", | ||
| "// an event log: every payload, in order", | ||
| "let events = stream::Producer::new(track, stream::ProducerConfig::default());", | ||
| ].join("\n"), | ||
| lang: "rust", | ||
| }, | ||
| { | ||
| slug: "auth", | ||
| eyebrow: "new crate: moq-auth 0.1.0", | ||
| title: "One **auth contract** for every relay.", | ||
| sub: "The request a relay sends per session, the grant an auth server answers with, the lease a session holds, and the JWT a client presents. Paths are patterns: `foo` is one broadcast, `foo/**` a subtree.", | ||
| code: [ | ||
| "$ moq auth generate --out key.jwk", | ||
| "$ moq auth sign --key key.jwk --root demo --publish 'bbb/**' > token.jwt", | ||
| "$ moq auth verify --key key.jwk < token.jwt", | ||
| ].join("\n"), | ||
| }, | ||
| { | ||
| slug: "room", | ||
| eyebrow: "@moq/room 0.2", | ||
| title: "A video call is **a path prefix**.", | ||
| sub: "Members are discovered from announcements. Camera, mic, and screenshare built in. No room server: joining is a token for the prefix. Native twin: `moq-room`.", | ||
| code: [ | ||
| 'const url = new URL("https://relay.example.com/meet/demo?jwt=...");', | ||
| "const connection = new Connection({ url });", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '88,103p' tools/cards/cards.ts
rg -n 'Connection\.Reload|connection\.established|local\.enabled|`@moq/room`|`@moq/net`' tools package.json bun.lock*Repository: moq-dev/moq.dev Length of output: 3109 🏁 Script executed: sed -n '80,112p' tools/cards/cards.ts
sed -n '1,180p' package.json
rg -n --glob '!bun.lock' 'new Connection|Connection\.Reload|connection\.established|new Local|local\.enabled|cameraEnabled|`@moq/room`' .Repository: moq-dev/moq.dev Length of output: 2955 🌐 Web query:
💡 Result: <source_evidence> Citations:
🌐 Web query:
💡 Result: <source_evidence> Citations: 🏁 Script executed: rg -n 'room|Connection|Local|cameraEnabled|enabled|established' README.md docs sites tools --glob '*.md' --glob '*.mdx' --glob '*.ts' --glob '*.tsx' 2>/dev/null | head -160Repository: moq-dev/moq.dev Length of output: 788 🏁 Script executed: python3 - <<'PY'
import json, tarfile, urllib.request, io
urls = [
"https://registry.npmjs.org/@moq%2Froom",
"https://jsr.io/@moq/room/meta.json",
]
for url in urls:
print("URL", url)
try:
with urllib.request.urlopen(url, timeout=15) as r:
data = r.read()
print("bytes", len(data))
if "npmjs" in url:
obj = json.loads(data)
print("versions", sorted(obj.get("versions", {}))[-12:])
for version in ("0.2.0", "0.2.1", "0.2.2"):
v = obj.get("versions", {}).get(version)
if v:
print("version", version, "tarball", v.get("dist", {}).get("tarball"))
else:
print(data[:1000].decode("utf-8", "replace"))
except Exception as e:
print(type(e).__name__, e)
PYRepository: moq-dev/moq.dev Length of output: 523 🌐 Web query:
💡 Result: <source_evidence> Citations:
🏁 Script executed: set -o pipefail
curl -kfsSL --max-time 20 'https://registry.npmjs.org/@moq%2Froom' |
python3 -c 'import json,sys; o=json.load(sys.stdin); print("versions:", sorted(o.get("versions",{}))); [print(v, o["versions"][v].get("dist",{}).get("tarball")) for v in ("0.2.0","0.2.1","0.2.2") if v in o.get("versions",{})]'
printf '\nJSR metadata:\n'
curl -kfsSL --max-time 20 'https://jsr.io/@moq/room/meta.json' | head -c 3000
printf '\nGitHub package/source candidates:\n'
curl -kfsSL --max-time 20 'https://api.github.com/repos/moq-dev/moq/contents/js' |
python3 -c 'import json,sys; print("\n".join(x["name"] for x in json.load(sys.stdin)))'Repository: moq-dev/moq.dev Length of output: 636 🏁 Script executed: set -o pipefail
python3 - <<'PY'
import json, urllib.request, ssl
ctx = ssl._create_unverified_context()
url = "https://registry.npmjs.org/@moq%2Froom"
with urllib.request.urlopen(url, context=ctx, timeout=20) as r:
o = json.load(r)
v = o["versions"]["0.2.0"]
print("version:", v.get("version"))
print("dependencies:", v.get("dependencies"))
print("peerDependencies:", v.get("peerDependencies"))
print("dist:", v.get("dist"))
PY
printf '\nGitHub room directory:\n'
curl -kfsSL --max-time 20 'https://api.github.com/repos/moq-dev/moq/contents/room' |
python3 -c 'import json,sys; print("\n".join(f"{x["type"]} {x["name"]} {x["download_url"]}" for x in json.load(sys.stdin)))'Repository: moq-dev/moq.dev Length of output: 1442 🏁 Script executed: set -o pipefail
python3 - <<'PY'
import io, json, tarfile, urllib.request, ssl
ctx = ssl._create_unverified_context()
urls = [
"https://registry.npmjs.org/@moq/room/-/room-0.2.0.tgz",
"https://registry.npmjs.org/@moq%2Froom/-/room-0.2.0.tgz",
]
for url in urls:
print("URL", url)
try:
with urllib.request.urlopen(url, context=ctx, timeout=20) as r:
data = r.read()
print("bytes", len(data))
t = tarfile.open(fileobj=io.BytesIO(data), mode="r:gz")
names = t.getnames()
print("\n".join(names))
for name in names:
if name.endswith((".js", ".d.ts", ".ts")):
text = t.extractfile(name).read().decode("utf-8", "replace")
if any(x in text for x in ("Connection", "class Local", "class Room", "enabled", "established")):
print("\n---", name, "---")
for i, line in enumerate(text.splitlines(), 1):
if any(x in line for x in ("Connection", "class Local", "class Room", "enabled", "established")):
print(f"{i}:{line}")
break
except Exception as e:
print(type(e).__name__, e)
PY
printf '\nGitHub root entries:\n'
curl -kfsSL --max-time 20 'https://api.github.com/repos/moq-dev/moq/contents/?ref=main' |
python3 -c 'import json,sys; print("\n".join(x["name"] for x in json.load(sys.stdin)))'Repository: moq-dev/moq.dev Length of output: 3126 🏁 Script executed: python3 - <<'PY'
import io, tarfile, urllib.request, ssl
ctx = ssl._create_unverified_context()
url = "https://registry.npmjs.org/@moq/room/-/room-0.2.0.tgz"
with urllib.request.urlopen(url, context=ctx, timeout=20) as r:
data = r.read()
t = tarfile.open(fileobj=io.BytesIO(data), mode="r:gz")
for name in [
"package/README.md", "package/package.json", "package/index.d.ts",
"package/local.d.ts", "package/room.d.ts", "package/local.js", "package/room.js"
]:
print(f"\n--- {name} ---")
print(t.extractfile(name).read().decode("utf-8", "replace"))
PYRepository: moq-dev/moq.dev Length of output: 23725 🏁 Script executed: python3 - <<'PY'
import json, urllib.request, ssl
ctx = ssl._create_unverified_context()
url = "https://registry.npmjs.org/@moq%2Fnet"
with urllib.request.urlopen(url, context=ctx, timeout=20) as r:
o = json.load(r)
v = o["versions"]["0.4.0"]
print("version:", v.get("version"))
print("tarball:", v.get("dist", {}).get("tarball"))
print("dependencies:", v.get("dependencies"))
PYRepository: moq-dev/moq.dev Length of output: 360 Enable the local participant in the room example.
🐛 Suggested fix- "new Local({ connection, identity }).cameraEnabled.set(true);",
+ "const local = new Local({ connection, identity });",
+ "local.enabled.set(true);",
+ "local.cameraEnabled.set(true);",🤖 Prompt for AI Agents |
||
| 'const identity = Path.from("alice");', | ||
| "", | ||
| "new Local({ connection, identity }).cameraEnabled.set(true);", | ||
| "const room = new Room({ connection, identity });", | ||
| ].join("\n"), | ||
| lang: "ts", | ||
| }, | ||
| { | ||
| slug: "play", | ||
| eyebrow: "moq-cli 0.12", | ||
| title: "Watch without **a browser**.", | ||
| sub: "`moq play` decodes H.264, H.265, AV1, Opus, and AAC with the platform's hardware decoder, into a native window synced to the speaker.", | ||
| code: [ | ||
| "$ cargo install moq-cli --features play", | ||
| "$ moq --connect https://relay.example.com/anon --broadcast my-stream.hang play", | ||
| "", | ||
| "# trade latency for a jittery link", | ||
| "$ moq ... play --delay 500ms", | ||
| ].join("\n"), | ||
| }, | ||
| { | ||
| slug: "lan", | ||
| eyebrow: "moq-cli 0.12", | ||
| title: "Mesh the LAN with **zero config**.", | ||
| sub: "`--cluster-lan` finds every MoQ process on the network over mDNS and meshes with it. No relay, no internet, no certificates. Relays join the same mesh with `[cluster.lan]`.", | ||
| code: [ | ||
| "# on the camera box", | ||
| "$ moq --cluster-lan --broadcast cam.hang import capture", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '103,130p' tools/cards/cards.ts
sed -n '163,173p' tools/cards/cards.ts
rg -n 'moq-cli|--features (capture|transcode|play)|import capture|transcode' . --glob '*.md' --glob '*.toml' --glob '*.ts' | head -90Repository: moq-dev/moq.dev Length of output: 2535 🏁 Script executed: #!/bin/bash
set -u
printf '%s\n' '--- tracked candidate files ---'
git ls-files | rg '(^|/)(Cargo\.toml|.*moq.*|.*cards.*)$' | head -120
printf '%s\n' '--- moq-cli references and feature declarations ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'moq-cli|name\s*=\s*"capture"|name\s*=\s*"transcode"|cfg\(feature\s*=\s*"(capture|transcode)"\)|features\s*=.*(capture|transcode)|enum .*Command|Import|Transcode' . | head -240
printf '%s\n' '--- repository links and setup references ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'github\.com/moq-dev/moq|moq\.dev|cargo install moq-cli|cargo add moq-cli' . | head -160Repository: moq-dev/moq.dev Length of output: 25663 🌐 Web query:
💡 Result: <source_evidence> Citations:
🌐 Web query:
💡 Result: <source_evidence> Citations:
Enable the feature required by each CLI example.
Suggested fix code: [
+ "$ cargo install moq-cli --features capture",
"$ moq --cluster-lan --broadcast cam.hang import capture",
...
code: [
+ "$ cargo install moq-cli --features transcode",
"$ moq --connect https://relay.example.com/anon --broadcast cam.hang transcode \\",🤖 Prompt for AI Agents |
||
| "", | ||
| "# anywhere else on the network", | ||
| "$ moq --cluster-lan --broadcast cam.hang play", | ||
| ].join("\n"), | ||
| note: "--cluster-lan-secret to keep strangers out", | ||
| }, | ||
| { | ||
| slug: "media", | ||
| eyebrow: "moq-video + moq-audio", | ||
| title: "Native media, **no ffmpeg**.", | ||
| sub: "`getUserMedia` and WebCodecs for Rust. Camera, screen, and mic capture. Hardware codecs on VideoToolbox, Media Foundation, NVENC, VAAPI, V4L2, and MediaCodec. wgpu rendering and echo cancellation.", | ||
| code: "$ cargo add moq-video --features capture,render\n$ cargo add moq-audio --features capture,playback", | ||
| note: "no system codecs to install", | ||
| }, | ||
| { | ||
| slug: "languages", | ||
| eyebrow: "8 languages, 1 wire", | ||
| title: "MoQ in **your language**.", | ||
| sub: "Rust and TypeScript implementations, plus Python, Kotlin, Swift, Go, Dart, and C over the same Rust core. A publisher in Python plays in Swift.", | ||
| code: [ | ||
| "$ cargo add moq-net", | ||
| "$ bun add @moq/net", | ||
| "$ pip install moq-rs", | ||
| "$ go get moq.dev/moq", | ||
| "$ dart pub add moq", | ||
| "# Kotlin: dev.moq:moq Swift: moq-dev/moq-swift C: libmoq", | ||
| ].join("\n"), | ||
| }, | ||
| { | ||
| slug: "gateway", | ||
| eyebrow: "moq-cli 0.12", | ||
| title: "Bridge **every protocol**.", | ||
| sub: "RTMP, SRT, WebRTC (WHIP/WHEP), and HLS in and out of MoQ, as either the server or the client. Chain stages over one connection.", | ||
| code: [ | ||
| "$ moq --connect https://relay.example.com/anon \\", | ||
| " import --broadcast event.hang srt --listen 0.0.0.0:9000 \\", | ||
| " -- export --broadcast event.hang hls --listen 0.0.0.0:8080", | ||
| ].join("\n"), | ||
| }, | ||
| { | ||
| slug: "transcode", | ||
| eyebrow: "moq-cli 0.12", | ||
| title: "Transcode **on demand**.", | ||
| sub: "`moq transcode` publishes an ABR ladder next to any broadcast. A rung is only decoded and encoded while someone watches it, and on NVIDIA the whole pipeline stays on the GPU.", | ||
| code: [ | ||
| "$ moq --connect https://relay.example.com/anon --broadcast cam.hang transcode \\", | ||
| " --rung 720:2500000 --rung 360:600000 --encoder nvenc --decoder nvdec", | ||
| ].join("\n"), | ||
| }, | ||
| ]; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Make the
noqdependency example valid TOML.The card displays three assignments to
moq-tokioin one[dependencies]table. TOML rejects a key defined more than once, so readers cannot use the example as shown. Keep one active assignment and show the other choices as comments or separate examples. (toml.io)🤖 Prompt for AI Agents