1. Getting started
On the web: open the clock, then click the time or press S to open the panel.
In Setup → Time source, choose Public API for time from the internet or
Computer clock to use this computer's time, including offline after the page has loaded.
Over the studio LAN: run Start Clock.command on macOS or python3 server.py
in the project directory. Python 3.9+ is sufficient; no additional packages are required. Keep the server running.
Control panel: http://SERVER-IP:8765/?control. The terminal shows the IP address; Ctrl+C stops the server.
2. Modes and shared settings
| Mode | Purpose |
| No parameter | Clock with panels opened by clicking the time. |
?control | Operator panel with a preview of the clean OBS output on larger screens. |
?display | Studio monitor: a clock protected against accidental editing. Press F for fullscreen. |
?obs | Clean output without the cursor, panels, SYNC/HOLD or server messages. |
URLs for the site you are currently using:
GitHub Pages / standalone: settings are stored in this browser. Other windows of the same
browser at the same address (protocol, host and port) receive changes. OBS has its own browser storage;
an ordinary web panel does not automatically control OBS or another computer. A different address or profile may have different settings.
Studio server: settings are shared over the LAN, including with OBS and other computers.
Changes typically arrive in about 0.5–1 second. Use one operator panel: simultaneous edits to the same timer list
use the last saved version. On other devices, use the server IP rather than localhost.
When opening a file directly through file://, storage sharing between windows depends on the browser.
Use an HTTP/HTTPS address when working with multiple windows.
3. Where the time comes from
- Public API: retrieves UTC from timeapi.io, normally every 5 minutes. Requires internet access and an available service.
- Studio server: reads the server computer's system clock every 10 seconds. Available only when running through
server.py.
Synchronize the server operating system with the appropriate NTP source; a green status does not verify its NTP configuration.
- Computer clock: uses this device's clock without network time requests. Different computers may have different offsets.
- Local time server: uses the optional
time_server.py proxy, which requires ntplib.
Enter the NTP host/IP and optional port in the NTP field. Enter the proxy URL in API server, for example http://192.168.7.20:15151.
Browsers cannot query NTP directly over UDP. An HTTPS page may block an HTTP proxy; on a LAN, opening the clock from the LAN server is the simplest option.
Between samples, the clock measures elapsed time locally. The first successful sample sets the time; later corrections are smoothed
at up to 50 ms/s. Samples taking more than 1.5 seconds are rejected, and requests have a 4-second timeout. If the connection is lost,
the clock continues from its last time reference. A large difference takes time to correct, indicated by ADJUST.
Timezone converts UTC to the selected zone and accounts for daylight saving time.
Changing the zone also recalculates timer targets from their saved local date and time, so it may change the countdown.
Set the correct zone before preparing timers.
| Status | Meaning |
| SYNC | The last synchronization succeeded and the sample is current. |
| HOLD | No sample, a request error or an outdated sample. The clock continues locally. |
| ADJUST | A difference greater than 100 ms is being corrected. Setup shows the remaining correction. |
| LOCAL | This computer's clock is selected; network synchronization is not verified. |
| SHIFT | The operator has applied a manual time offset. This can appear alongside another status. |
Show sync status in the Clock tab hides the entire SYNC/HOLD/ADJUST/LOCAL/SHIFT indicator.
It does not disable synchronization. The choice is saved and shared with displays within the selected operating mode.
OBS output always hides this indicator. Server connection information is separate diagnostics, available in the panel.
RTT is the response time; offset is the correction to the time reference. Hundredths of a second are a display format,
not an accuracy guarantee. This is not genlock, LTC or frame synchronization. Monitor and OBS video-path latency
is added independently; check the actual video path before going on air.
4. Timers and manual offsets
- In Timers, click Add Timer.
- Enter a label and target date/time in the selected zone.
- Click Save. The switch in each row shows or hides that timer.
Before the target, the timer displays a minus sign and counts down to zero. After the target, it displays a plus sign and elapsed time.
This is a countdown to a deadline, not a stopwatch with start/pause controls. Reset clears the target; Delete removes the timer.
Reset All Timers clears all targets after confirmation.
Each timer can have a base color; Auto uses the global Normal color.
Warning and Urgent override that color before the target; Passed applies afterwards. The default thresholds are 15 and 5 minutes.
Custom accepts your own thresholds, including zero. The red threshold takes priority.
In Clock Shift, enter the sign and offset, then click Apply Offset.
You can also enter and apply a specific date/time. Typed values do not change the output until you apply them.
Reset Shift returns to the source time. The offset also affects timers; it does not independently delay one display.
5. Appearance and keyboard controls
The Clock tab controls synchronization status, the dial-free layout, hundredths of a second, the date, clock scale and dial style.
Setup → Colors controls the background, clock/dial color and timer-state colors. Reset colors restores the default palette.
F — fullscreen; S — panels; G — dial/simple layout;
Shift+R — reset all targets after confirmation. Editing shortcuts are disabled in display/obs,
while typing in fields and while help is open. Esc closes help.
6. Adding the clock to OBS and monitors
- Add a Browser source and turn off Local file.
- Paste the
?obs URL listed above. - Set 1920 × 1080 and 50 or 60 FPS to match your project.
- Turn off Shutdown source when not visible and Refresh browser when scene becomes active to keep the page loaded between scenes.
- Use the source in a scene. OBS handles output/projector display and further transmission.
GitHub Pages can provide the clock image to OBS, but shared control from an external panel requires the LAN server.
To change standalone settings inside OBS, use Interact with a URL without ?obs,
then return to the clean view in the same source and check that the settings are retained.
On a studio monitor, open ?display and press F. The default background is black, not transparent.
7. Troubleshooting
CLOCK ERROR: rendering failed or animation frames stopped. The warning hides potentially stale
clock and timer output, including in OBS, independently of the sync-status switch. Rendering retries automatically;
a watchdog checks every two seconds and restarts a stalled loop, normally within 2–4 seconds. The warning clears
after two seconds of successful visible frames. Setup retains the last error. If it persists, inspect Setup and
the browser console, correct the cause or reload the source.
Normal hidden-tab suspension does not trigger this warning. The watchdog cannot show an alarm while the
browser thread is completely blocked, the browser has crashed or the computer is asleep.
- HOLD: check Time source and the details in Setup. Public API requires internet access;
for offline use, select Computer clock or the studio server.
- Defaults restored: the server recovered corrupt saved state. The original bytes remain
in the named
state.json.*.bad backup beside the state file. Verify timers and settings before use.
- Screen sleep: display and OBS views request a screen wake lock when supported.
It may be denied on insecure LAN HTTP or released by the browser; configure the operating system to keep the monitor awake.
- Server offline: check that
server.py is running, the IP/port is correct and the devices can connect over the LAN.
Settings refresh automatically when the connection returns.
- Changes pending: keep the panel open. Changes will be sent after reconnection; the queue is held in the open window's memory.
- Changes do not reach OBS: GitHub Pages uses separate browser sessions. Use the shared LAN server.
On a LAN, compare the panel and OBS source addresses.
- Wrong time: check Timezone, Clock Shift, the computer/server clock and ADJUST status.
- Missing timer: check its row switch and whether its target was reset. After passing the target, it should continue counting with a plus sign.
- Missing font or scripts after publishing: upload index.html, assets/, font/ and optional media/ together.
Reload the page without cache; in OBS, refresh the source cache.
8. GitHub Pages, saving and moving settings
The same files work as a standalone site and with the optional LAN server.
GitHub Pages serves HTML/JS/CSS and does not run Python. The mode is detected without querying a nonexistent API.
Display URLs preserve the project directory, for example /BRC/?display.
Publish index.html, all of assets/, font/ and media/ if you use a logo.
Updating index.html alone is not sufficient. Do not publish data/ or studio configuration.
Editing local files does not update the GitHub site; publishing is a separate step.
Standalone settings are stored in localStorage: clearing site data or closing a private profile may delete them.
LAN settings are stored in data/state.json; back up this file while the server is stopped.
When a new server is first opened, the panel attempts to import old settings available in the same browser at the same address.
The LAN server is intended for a trusted studio network and has no panel login. Do not expose its port as a public control panel on the internet.