This repository contains a complete, production‑ready control server and web‑based user interface for synchronised playout across up to twenty CasparCG playback nodes. It solves the common problem of keeping multiple SDI/NDI feeds in frame‑accurate sync and provides a modern, dark‑themed dashboard for configuring and operating your playout.
- 20 independent slots – each slot represents a single clip on a remote CasparCG server. You can assign host, port, channel, base layer, file name and start timecode per slot.
- Always‑available blank slot – the GUI always adds an extra empty row at the bottom of the slots table. When you fill in the last row and save, a new blank row will appear on reload; clearing all fields (and unticking the Active box) and saving will remove that slot. There is effectively no hard limit on how many slots you can configure.
- Active toggle per slot – each slot has a checkbox to enable or disable it. Only those with the Active box checked will be controlled by the server. Disabled slots remain in the configuration but do not send commands or appear in the status view.
- Sensible defaults – new slots default to host
127.0.0.1, port5250, channel1, base layer10and timecode00:00:00:00. These values can be changed per slot as needed. - Frame‑accurate synchronisation – the server maintains a common start time (
t0) and periodically compares the playing frame of each slot to the expected frame. When drift exceeds a configurable tolerance the system performs a seamless resync using a second hidden layer and either a hard cut or a short fade (cross‑fade). - Manual or automatic operation – choose between OFF, MANUAL and AUTO modes. Manual mode lets you trigger resyncs on demand, while Auto mode keeps your feeds aligned at a user‑defined interval.
- Timecode support – for each slot you can enter a starting timecode in
HH:MM:SS:FFformat. During playback the clip will seek to that frame before starting, allowing you to cue different portions of a file across your feeds. - Persistent configuration – all settings (global and per‑slot) are stored in
config.jsonon the server. Changes via the web interface are saved so that reloading the page or connecting from another browser will reuse the same settings. - Modern dark‑themed GUI – built with vanilla HTML/CSS/JS, the interface uses a sleek dark mode with subtle colour coding for different states (e.g. green for in‑sync, red for drift, blue for current mode). Responsive design ensures it looks good on tablets and desktops.
- WebSocket status updates – the dashboard updates in real time via WebSockets to show current frame, target frame and drift for each slot without manual refreshing.
- Ready for Windows – the code and instructions below assume a Windows environment for ease of installation. It will run equally well on Linux or macOS with minimal adjustments (replace Windows‑specific commands with their UNIX equivalents).
casparcg-auto-sync/
├── README.md – You are reading it now.
├── package.json – NPM metadata and dependencies.
├── index.js – The Node.js control server.
├── config.sample.json – Template configuration with 20 empty slots.
├── config.json – Generated by the application; holds your live settings.
└── public/
├── index.html – The browser GUI.
├── style.css – Dark theme styling for the GUI.
└── script.js – Client‑side logic (fetching status, sending commands, persisting values).
- Node.js ≥ 18 – download and install from nodejs.org. The application uses ECMAScript modules (
type: moduleinpackage.json), so Node 18 or later is recommended. - Git – to clone this repository and version control your changes.
- CasparCG servers – up to twenty machines running CasparCG server (preferably the latest LTS build). Each server should expose the AMCP control port (default
5250) and have the desired clips in its media folder.
- Clone the repository
git clone https://github.com/yourusername/casparcg-auto-sync.git
cd casparcg-auto-sync- Install dependencies
npm install- Prepare a configuration file
Copy the provided sample and edit it:
cp config.sample.json config.jsonOpen config.json in a text editor and fill in the settings:
fps– the frame rate of your material (e.g.50for 1080p50,29.97for NTSC drop frame). Use consistent fps across all slots.frames– the total number of frames in a loop for the purpose of wrapping the modulo calculation. If your longest clip is five minutes at 50 fps, set this to5*60*50 = 15000. It is not a hard limit – it simply determines when the timer resets. Choose a value equal to or greater than the length of your longest clip.autosyncIntervalSec– number of seconds between drift checks in AUTO mode. Lower values mean quicker corrections but more network chatter.driftToleranceFrames– maximum allowed frame drift before a resync is triggered. A value of1keeps clips within ±1 frame.resyncMode– either"cut"or"fade". A cut performs an instant switch; a fade usesfadeFramesframes to cross‑fade.fadeFrames– number of frames for a cross‑fade whenresyncModeis"fade".slots– an array of objects (20 entries by default). Each slot must define at leasthost,channel,baseLayerandclipto be active.timecodeis optional and defaults to"00:00:00:00".
Example slot configuration:
{
"name": "Slot 1",
"host": "192.168.10.21",
"port": 5250,
"channel": 1,
"baseLayer": 10,
"clip": "my_video.mov",
"timecode": "00:03:24:05"
}If you leave host or clip blank, that slot will be ignored (no connection attempt will be made).
- Start the server
npm startThe server will bind to localhost:8080 by default and read config.json. It also creates a WebSocket at the same port for live updates. You can change the listening port by setting the PORT environment variable:
PORT=9000 npm start- Open the web interface
Navigate to http://localhost:8080 in your browser. The page will load your current configuration. Any changes you make to slots or global settings can be saved with the “Save Config” button. Starting playback with the “Start” button will call PLAY and SEEK on all active slots simultaneously.
- Preload before starting – clicking Preload loads all clips into memory on each Caspar node, ready to play. It does not make the layers visible. Use this if you want to warm up your servers before the actual start.
- Start – begins playback from the specified timecodes on all active slots and sets the common start time (
t0). It also makes the active layer visible (opacity 1) and mutes the standby layer. You can click Start multiple times; each time resetst0and restarts all clips. - Pause – pauses playback on both active and standby layers across all slots. Resume by pressing Start again (resets
t0). - Resync – performs an immediate sync according to the selected resync mode (cut or fade). This is useful in MANUAL mode to correct drift on demand. In AUTO mode the system will call resync itself whenever drift exceeds the tolerance.
- Modes – choose OFF (no automatic resyncs), MANUAL (only manual resync), or AUTO (periodic resync). The current mode is displayed next to the buttons.
- Fade vs Cut – use Cut for hard switches (no cross‑fade), and Fade for a subtle cross‑fade. The
fadeFramesfield defines how long (in frames) the cross‑fade lasts.
- Commenting and readability – all JavaScript files contain extensive comments explaining the purpose of functions, parameters and internal data structures. Even if you are not a coder, you should be able to follow how the pieces fit together.
- Modularity – the server logic is separated from the front‑end UI. The
script.jsfile handles all browser interaction and communicates with the server viafetch(for commands and config) and WebSocket (for live status). - CasparCG version – this application targets the latest CasparCG LTS release (currently 2.3.x). It uses the casparcg‑connection package to talk to the AMCP protocol. Should you upgrade to a future version, no changes are expected unless AMCP semantics change.
- Persisting settings – saving configuration updates
config.jsonon disk. If the file is missing at startup, the server will fall back toconfig.sample.json. Feel free to commitconfig.sample.jsonto version control and addconfig.jsonto.gitignore(already done) to avoid pushing your personal settings. - Windows services – to run this control server as a service on Windows, you can use NSSM or Task Scheduler to run
npm starton boot. Make sure Node and your project folder are accessible to the service account. - Reverse proxy – in a production environment you may wish to proxy the web app through IIS, Nginx or Apache and enable HTTPS. Forward incoming requests on the appropriate port to your Node process (
localhost:8080).
- Cannot connect to CasparCG servers – check that each
hostis reachable from the machine running this control app. Verify that the AMCP port (5250) is open and allowed through firewalls. Usetelnet <host> 5250to test connectivity. - No video output – ensure the
channelandbaseLayernumbers match your CasparCG configuration (casparcg.config). Layers must not collide with other content being rendered on the same channel. - Drift never corrects – confirm that all slots have identical frame rate files (e.g. all are 50 fps). Mixed fps will cause drift. Also, verify that the timecode you entered is valid; if the frame part exceeds
fps – 1, it will wrap into the next second. - High CPU – reducing
autosyncIntervalSecincreases the frequency of AMCP commands. Increase the interval if your system becomes sluggish.
Contributions and suggestions are welcome! Please open issues or pull requests on the GitHub repository. This project is intended to be a community resource for anyone building multi‑channel play‑out systems with CasparCG.