Web Development/3 min read
A podcast studio CMS with a remote-controlled teleprompter
How I built Silicon for KEI Creations, a podcast studio CMS with a teleprompter that several devices control in real time over WebSockets, plus an Electron app for timed questions.
In 2022 I did my internship at KEI Creations in Groningen. One of the projects was Silicon, a system for their podcast studio. During a recording a lot happens at once: a host reads from a script, someone in the control room manages timing, and guests answer questions that have to come up at the right moment. Silicon brought that together in one place.
What it does
- A CMS where the team uploads videos, audio and scripts for each episode.
- A teleprompter that shows the script during recording.
- Remote control of that teleprompter from several devices at once over WebSockets.
- An Electron app that loads timed questions and runs a timer, with stops and pauses.
The stack: Vue.js for the frontend, a Symfony (PHP) API with MySQL for the CMS, and Node.js for the real-time parts.
The teleprompter
A teleprompter sounds simple: scroll text. In practice the person reading needs control over how it looks and moves:
- scroll speed,
- font size, so it's readable from wherever the camera is,
- background and text colour, for contrast under studio lights,
- play and stop.
The teleprompter itself runs in a browser on the screen in front of the host. The interesting part is who controls it.
One shared state over WebSockets
The host shouldn't have to touch the teleprompter while talking. Someone in the control room, or the host from a phone, should be able to pause it or slow it down, and every screen should update instantly.
That's the job of a small WebSocket server in Node.js using the ws library. The design is deliberately simple: the server owns one shared state, and every client just mirrors it.
let state = {
running: false,
fontSocketValue: 50,
speedSocketValue: 1,
socketBgColor: '#000000',
socketFontColor: '#ffffff',
};The protocol has two message types:
- Clients send a request with an action:
play,stop,fontReSize,changeSpeed,changeBackGroundColororchangeFontColor, plus a value. - The server updates the state and sends a response with the full state to every connected client.
A new client gets the current state the moment it connects, so a phone that joins halfway through a recording shows the right speed and colours straight away. Because every client always receives the whole state rather than a change, a missed message can't leave a screen out of sync: the next update fixes it.
The Electron app for timed questions
Interviews follow a schedule: a question at minute 5, a break at 20, the closing question at 45. The Electron desktop app loads those timed questions and runs a timer with stops and pauses, so the producer can see what's next and keep the episode on time. Electron made sense here because it runs as a normal desktop app in the control room, while reusing web technology the team already knew.
Working in a real team
This was my first time building for real users in production. Besides the code, the internship meant doing requirements analysis with the studio team, adapting systems to what they actually needed, and maintaining back end, front end and database once things were live.
Looking back
Some things I'd do differently now:
- Validate messages. The server trusts every message and would crash on invalid JSON. A
try/catcharound parsing and a whitelist of actions and value ranges would make it robust. - Separate updating from broadcasting. The server applies the change and then sends the state to each client in the same loop. Applying it once and then broadcasting is cleaner and easier to test.
- Authenticate clients. Anyone on the network who knew the port could control the prompter. Fine for a closed studio network, but a simple shared token would close that gap.
The core idea still holds up, though: for a handful of devices controlling one thing, a single source of truth that broadcasts its full state is about the simplest real-time design that works.
Blog / Keep reading
Related articles.
Web Development/4 min read
CourseCraft, a course website from a folder of videos
A zero-dependency Node.js app that turns course folders into a website.
Web Development/4 min read
Building JamSesh, a place for musicians to find each other
A Go and PostgreSQL backend with real-time chat for a musician platform.
Web Development/4 min read
Building a real-time "guess 80% of the average" game
A Socket.io multiplayer game inspired by Alice in Borderland's Balance Scale.