No description
  • JavaScript 77.5%
  • CSS 12.2%
  • HTML 10.3%
Find a file
2026-07-05 21:04:21 +00:00
.claude init 2026-07-05 16:26:04 -04:00
deploy simple stuff 2026-07-05 21:04:21 +00:00
.env.example simple stuff 2026-07-05 21:04:21 +00:00
.gitignore simple stuff 2026-07-05 21:04:21 +00:00
admin.html init 2026-07-05 16:26:04 -04:00
admin.js init 2026-07-05 16:26:04 -04:00
app.js init 2026-07-05 16:26:04 -04:00
DEPLOYMENT.md simple stuff 2026-07-05 21:04:21 +00:00
index.html init 2026-07-05 16:26:04 -04:00
README.md init 2026-07-05 16:26:04 -04:00
schedule.json init 2026-07-05 16:26:04 -04:00
server.js init 2026-07-05 16:26:04 -04:00
style.css init 2026-07-05 16:26:04 -04:00

Online Theater

A small website that plays scheduled videos at their scheduled times, keeping every viewer in sync with the schedule — like a movie theater. Latecomers join the show in progress; everyone sees (roughly) the same frame at the same moment. Shows are managed on an admin page.

Running it

node server.js
# theater:  http://localhost:8741
# admin:    http://localhost:8741/admin

No dependencies — just Node. The schedule is stored in schedule.json next to the server.

Scheduling shows

Open /admin and add a show: title, video URL (an MP4 the browser can play), and showtime. Shows can be deleted from the same page. The admin page is currently not access-controlled — anyone who knows the URL can edit the schedule.

Hosting video files next to the site is easiest: drop show.mp4 in this folder and use show.mp4 as the URL (the server supports HTTP range requests, which browsers need for seeking). If the video lives on another host/CDN, that server must send CORS headers or the pre-load step will fall back to streaming.

How a showing works

  1. Lobby — visitors see a countdown to the next show and click "Take your seat" (the click is required so the browser allows playback with sound).
  2. Pre-load — starting 10 minutes before showtime, the video is quietly downloaded into memory so playback never buffers. If it can't finish in time (or the host blocks cross-origin fetch), the site falls back to normal streaming.
  3. Showtime — the video starts automatically, seeked to now showtime so latecomers join mid-show. A background check re-syncs anyone who drifts more than 3 seconds from the schedule.
  4. Next show — when the film ends, viewers return to the lobby, which counts down to the next scheduled show. The lobby refreshes the schedule every 30 seconds, so admin changes appear without a reload. Shows with a bad video URL are skipped with a notice.

Testing

Append ?in=30 to the theater URL to fake a test show starting 30 seconds from page load (this ignores the real schedule).

API

  • GET /api/schedule — list shows, sorted by showtime
  • POST /api/schedule — add a show: {title, videoUrl, showtime} (ISO date)
  • DELETE /api/schedule/<id> — remove a show

Download vs. stream — the tradeoffs

  • Streaming (just pointing <video> at a URL) is the simple, standard path: playback starts instantly, works for any file size, and the browser only fetches what it needs. Risk: a viewer with a slow connection may see buffering mid-show.
  • Full download first guarantees stutter-free playback, but viewers must arrive early enough to finish the download, it holds the whole file in memory (impractical past a few hundred MB, especially on phones), and a true "save to disk" version adds a lot of complexity for no real benefit.
  • This site does a hybrid: it streams by default, but pre-fetches the file into memory in the minutes before showtime when possible. You get the no-buffering guarantee of a download with the graceful fallback of streaming.

For a bigger audience or longer films, the next step up is converting the video to HLS (segmented streaming) and serving it from a CDN — same page logic, better scalability and adaptive quality.