/* RADAR1 — Program Out: stage composition, layout state machine, scaling */ const DSa = window.Radar1DesignSystem_1f4661; const STAGE_W = 1920, STAGE_H = 1080, HERO_W = 1280, HERO_H = 720, MARGIN = 48, RAIL_GAP = 44, INFO_H = 64; const APP_DEFAULTS = { layout: "A", auto: true, mode: "normal", heroScene: "studio", tile: null, boxes: 0, cams: [], camTimes: {}, countdown: false, h24: true, l3Variant: "story", insets: { l3: true, ots: false, phone: false, map: false, loc: false, source: false }, }; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "tickerDur": 46, "railDwell": 18, "swapMin": 10, "safeGuides": false, "backdrop": "auto" }/*EDITMODE-END*/; function loadState() { try { const raw = localStorage.getItem("r1-program-v1"); if (!raw) return APP_DEFAULTS; const p = JSON.parse(raw); const merged = { ...APP_DEFAULTS, ...p, insets: { ...APP_DEFAULTS.insets, ...(p.insets || {}) } }; if (merged.mode === "critical") merged.mode = "situation"; /* legacy name */ if (merged.mode !== "normal" && merged.mode !== "situation") merged.mode = "normal"; if (merged.tile === "cutspot" && !(window.R1DATA || {}).cutspot) merged.tile = null; /* persisted spot with no content — don't blank the hero */ return merged; } catch (e) { return APP_DEFAULTS; } } /* ---------- Hero inset (1280×720 framed program video) ---------- */ function HeroInset({ st, h24 }) { const now = useNow(); const ins = st.insets; const tileActive = !!st.tile, boxesActive = st.boxes > 0; const situation = st.mode === "situation"; const showL3 = ins.l3 && !tileActive; const TileComp = tileActive ? window.TILES[st.tile].comp : null; return (
{/* content layer — program video is keyed in downstream: the inlay is a clean chroma hole. Magenta: green/blue/cyan all collide with our signal accents; nothing in the package is magenta. */} {tileActive ? : boxesActive ? :
} {/* scrim under lower third (never over the chroma hole — it would spoil the key) */} {showL3 && tileActive && (
)} {/* dressings */} {ins.ots && !tileActive && !boxesActive && !ins.phone && } {ins.phone && !tileActive && !boxesActive && } {ins.map && !tileActive && } {showL3 && } {/* hairline frame drawn OVER the feed — content box stays a true 1280×720 */}
); } /* ---------- Corner flag (unused in current modes; kept for future events) ---------- */ function CornerBrand() { return null; } /* ---------- Animated stage backdrop (subtle, 4 looks, slow crossfade) ---------- */ const BACKDROPS = ["sweep", "grid3d", "spotlight", "lake"]; /* deterministic droplet field for the lake look */ const LAKE_DROPS = Array.from({ length: 9 }, (_, i) => { let s = i * 971 + 31; const r = () => (s = (s * 16807) % 2147483647) / 2147483647; return { x: 4 + r() * 90, y: 10 + r() * 78, dur: 5 + r() * 4, delay: -r() * 9, size: 220 + r() * 260 }; }); function StageBackdrop({ mode, situation }) { const auto = mode === "auto" || !BACKDROPS.includes(mode); const ai = useCycle(BACKDROPS.length, 150000); const active = situation ? "sweep" : (auto ? BACKDROPS[ai] : mode); const beam = situation ? "rgba(228,3,46,0.05)" : "rgba(31,168,224,0.065)"; const beamFaint = situation ? "rgba(228,3,46,0.014)" : "rgba(31,168,224,0.018)"; const layer = (name, on, children) => (
{children}
); const GRID_C = 20, GRID_R = 12; return (