OBS scene utilities for ATProto PDX meetups sites.wisp.place/graham.systems/obs
0

Configure Feed

Select the types of activity you want to include in your feed.

5 1 0

Clone this repository

https://tangled.org/graham.systems/atproto-pdx-scenes https://tangled.org/did:plc:vyg5ly3yohnkrxdnr2hg245c
git@tangled.org:graham.systems/atproto-pdx-scenes git@tangled.org:did:plc:vyg5ly3yohnkrxdnr2hg245c

For self-hosted knots, clone URLs may differ based on your setup.



README.md

ATProto PDX stream scenes#

One procedural background for the whole meetup stream: a Truchet tile board of winding paths that quietly rearranges itself, one snappy rose tile-flip at a time. A single self-contained page (index.html, fonts embedded, no network needed) watches OBS state through the injected window.obsstudio API and recasts itself per scene:

  • Starting Soon — copy block with date/time, lively cadence (a flip every second or so)
  • Thank You — copy block with a sign-off note, the board winding down
  • Background — no text, full-frame board at a middle cadence, for layering slides or screen shares on top

When the stream goes live (obsStreamingStarted), the board plays a wavefront of flips radiating from center and the text replays its entrance. The text entrance also plays on scene changes — but not on page load, so the animation is saved for moments viewers actually see, and the source can stay loaded all stream without cold canvas starts.

OBS setup#

Add one Browser Source and reuse it in every scene that wants the board:

  1. Leave Local file unchecked and put the file path in URL so you can pass parameters, e.g. file:///home/graham/atproto-pdx-scenes/index.html?when=Thursday, July 16 · 6:30 PM (file:///C:/Users/graha/... on Windows)
  2. Width 1920, Height 1080
  3. FPS 30 (check "Use custom frame rate") — the page also caps itself at 30
  4. Leave Shutdown source when not visible and Refresh browser when scene becomes active unchecked — the page is designed to stay resident and react to events
  5. Set Page permissions to at least "Read access to OBS status information" so the page receives scene and streaming events

Scene name mapping#

On every obsSceneChanged, the page matches the new scene's name (case-insensitive substring) to pick its mode:

Mode Default keywords Override param
Starting Soon soon, intro, preshow, pre-show ?soonMatch=a,b,c
Thank You thank, outro, end, bye ?thanksMatch=a,b,c
Background anything else

So scenes named "Starting Soon", "Intro", "Thanks + Outro" just work; if your scene names don't fit, pass your own keyword lists.

Text parameters#

All text is set via URL query parameters; no code edits on event night. Pass an empty value (e.g. &handle=) to hide that line.

Param Default Used in
title ATProto PDX both text modes
handle @pdx.atproto.camp both text modes
status Starting soon Starting Soon
when (hidden) Starting Soon — pass explicitly, e.g. ?when=Thursday, July 16 · 6:30 PM
thanksStatus Thanks for watching Thank You
note See you at the next one. Thank You
mode soon initial mode before any OBS event, and the mode used outside OBS (soon/thanks/bg)

Live chat#

In the Starting Soon and Thank You modes, the page shows the stream.place chat for the channel in a column at bottom-right. It subscribes to a Jetstream firehose for place.stream.chat.message records and keeps the ones whose streamer DID matches the channel. Author DIDs resolve through their DID document (PLC directory or did:web) to get the handle plus PDS, then the chatter's place.stream.chat.profile is fetched for their chosen name color (dark colors are lifted to a legibility floor for the slate background; chatters without one get the house rose). Everything is cached per DID. Record deletions on the firehose remove the message from the overlay, so moderation actions are honored. The last 8 messages show, oldest fading out through a mask. Live-only: messages sent before the page loaded don't appear.

Chat requires network access from the browser source; if offline, it reconnects with backoff and the rest of the scene is unaffected.

Param Default
channel pdx.atproto.camp the streamer whose chat to show (handle or DID)
jetstream wss://jetstream2.us-east.bsky.network/subscribe alternate Jetstream instance
chat on pass chat=off to disable entirely

Previewing outside OBS#

Open the page in any browser (python -m http.server 8143, then http://localhost:8143/). Without window.obsstudio the entrance plays on load, and keyboard controls stand in for OBS events:

Key Action
1 / 2 / 0 switch to Starting Soon / Thank You / Background
r small ripple
l simulate going live: board-wide ripple + text entrance
c inject a demo chat message

window.__spChat in the console shows chat connection state (connected, resolved channel DID, messages shown/dropped) for debugging.

If the host machine struggles#

The scene is light (144 arc tiles redrawn at a capped 30fps, most frames identical), but if rehearsal shows the encoder fighting for headroom, screen-record 60–90 seconds and swap the Browser Source for a looping Media Source — same look, decode-only cost (you lose the OBS-event reactivity).

Design notes#

Palette, typography, and motion rules live in DESIGN.md; strategic context in PRODUCT.md.