- JavaScript 77.5%
- CSS 12.2%
- HTML 10.3%
| .claude | ||
| deploy | ||
| .env.example | ||
| .gitignore | ||
| admin.html | ||
| admin.js | ||
| app.js | ||
| DEPLOYMENT.md | ||
| index.html | ||
| README.md | ||
| schedule.json | ||
| server.js | ||
| style.css | ||
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
- 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).
- 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.
- Showtime — the video starts automatically, seeked to
now − showtimeso latecomers join mid-show. A background check re-syncs anyone who drifts more than 3 seconds from the schedule. - 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 showtimePOST /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.