screentinker/Examples/PIP-Event-Countdown/countdown-overlay.js
ScreenTinker ab771ec595 Add PiP overlay example recipes
Self-contained examples for the PiP overlay API (POST /api/pip), each
with a CSP-safe query-param overlay (external JS), config.example.json,
zero runtime deps, an offline test, and a README:

- PIP-Announce-Broadcast    manual one-shot message to a screen/group
- PIP-Weather-Widget        Open-Meteo current conditions (keyless)
- PIP-Air-Quality           Open-Meteo US AQI widget (keyless)
- PIP-Crypto-Ticker         CoinGecko price strip (keyless)
- PIP-News-Ticker           scrolling RSS/Atom headlines
- PIP-Room-Status-Calendar  ICS-driven Available/Busy room sign
- PIP-Event-Countdown       client-side countdown, auto-clears at zero
- PIP-Welcome-Board         rotating welcome/birthday cards from CSV
- PIP-Fundraiser-Thermometer goal-progress bar from local/URL JSON
- PIP-QR-Rotator            rotating QR codes, encoded client-side
- PIP-Incident-Webhook      event-driven: red on firing, clear on resolved

Also includes the CAP-AU (NSW RFS) and US NWS/NOAA emergency-alert
monitors that push expiry-aware PiP overlays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 20:17:38 -05:00

54 lines
1.9 KiB
JavaScript

// External overlay script — same-origin so the server CSP (scriptSrc 'self') permits it.
// Reads ?target (epoch ms) and ?title from the URL and ticks a live DD:HH:MM:SS clock.
// When the target arrives it switches to a celebratory state. The PiP itself is removed
// by the player at the same moment (duration = seconds-to-target), so this is the visual
// that the viewer sees right before it vanishes.
(function () {
var q = new URLSearchParams(location.search);
var target = parseInt(q.get('target'), 10);
var title = (q.get('title') || 'Countdown').trim();
document.getElementById('title').textContent = title;
var pad = function (n) { return (n < 10 ? '0' : '') + n; };
var elD = document.getElementById('d');
var elH = document.getElementById('h');
var elM = document.getElementById('m');
var elS = document.getElementById('s');
var clock = document.getElementById('clock');
var card = document.getElementById('card');
function tick() {
var secs = Math.ceil((target - Date.now()) / 1000);
if (!isFinite(target)) { return; }
if (secs <= 0) {
celebrate();
return;
}
var s = secs;
var days = Math.floor(s / 86400); s -= days * 86400;
var hours = Math.floor(s / 3600); s -= hours * 3600;
var mins = Math.floor(s / 60); s -= mins * 60;
elD.textContent = pad(days);
elH.textContent = pad(hours);
elM.textContent = pad(mins);
elS.textContent = pad(s);
}
var celebrated = false;
function celebrate() {
if (celebrated) { return; }
celebrated = true;
clearInterval(timer);
clock.classList.add('done');
elD.textContent = '00'; elH.textContent = '00'; elM.textContent = '00'; elS.textContent = '00';
var c = document.createElement('div');
c.className = 'celebrate';
c.textContent = '🎉 ' + title;
card.appendChild(c);
}
tick();
var timer = setInterval(tick, 1000);
})();