/* eslint-disable */ /* Screens 4–6. Scene area is 1380 × 900. */ /* ============================================================ SCREEN 4 — Use Cases ============================================================ */ function Screen4({ onNext, onBack, useCaseIndex, setUseCaseIndex, videoOpen, setVideoOpen }) { const useCases = [ { n: "01", title: "Cross-domain Signalling / Rolling Stock", short: "Signalling × RS" }, { n: "02", title: "SW / HW evolvability", short: "SW/HW evolvability" }, { n: "03", title: "Resilience / track anomaly / weather", short: "Resilience" }, { n: "04", title: "Individualized doors behaviour", short: "Doors behaviour" }, { n: "05", title: "Software Upgrade / App Store", short: "App Store" }, { n: "06", title: "Improve train performances", short: "Performance" }, ]; const current = useCases[useCaseIndex]; return ( {/* Title */}
Discover the SDT use cases
Six use cases — click any tile to play its video.
{/* 6 tiles aligned at the bottom — title on top, small thumbnail below */}
{useCases.map((uc, i) => { const isActive = videoOpen && i === useCaseIndex; return (
{ setUseCaseIndex(i); setVideoOpen(true); }} style={{ border: isActive ? "1.5px solid var(--accent)" : "1px solid var(--ink)", background: isActive ? "var(--accent-soft)" : "var(--paper)", padding: 10, cursor: "pointer", display: "flex", flexDirection: "column", gap: 8, transition: "border-color 0.15s, background 0.15s", }} > {/* Title row above the thumbnail */}
{uc.n}
{uc.title}
{/* Small thumbnail */}
); })}
{/* Video popup — immersive: title overlaid on the video, no header band, no prev/next. */} {videoOpen && (
{/* Player */}
{/* Title overlay on the video */}
{current.title}
{/* Close button overlay */}
{/* Bottom controls — play/pause + scrubber only */}
00:42 / 01:58
)}
); } /* ============================================================ SCREEN 5 — Value Customer Benefits ============================================================ */ function Screen5({ onNext, onBack, activeBenefit, setActiveBenefit }) { const benefits = [ { n: "01", label: "Operators", pitch: "Streamlined operations and easier piloting." }, { n: "02", label: "Maintainers", pitch: "Predictive maintenance and reduced downtime." }, { n: "03", label: "Passengers", pitch: "A smoother, more personalised journey." }, { n: "04", label: "Public authorities / lessors", pitch: "A future-proof, evolvable investment." }, ]; return (
Value · customer benefits
Four pillars — click a pillar to expand its value.
{benefits.map((b, i) => { const isActive = activeBenefit === i; const isDim = activeBenefit !== null && !isActive; const flex = isActive ? 2.6 : (activeBenefit !== null ? 0.8 : 1); return (
setActiveBenefit(isActive ? null : i)} style={{ flex }} >
{b.n}
{isActive ? (
{b.label}
{b.pitch}
Benefit keywords
keyword keyword keyword
{ e.stopPropagation(); setActiveBenefit(null); }}>← Collapse
) : (
{b.label}
)}
); })}
); } /* ============================================================ SCREEN 6 — Video globale ============================================================ */ function Screen6({ playerState, setPlayerState, onBack, onReset }) { // "launch" | "playing" | "ended" const [progress, setProgress] = useState(0.38); // Make the scrubber actually act as the timeline const scrubberRef = useRef(null); const draggingRef = useRef(false); const setFromEvent = (e) => { const el = scrubberRef.current; if (!el) return; const r = el.getBoundingClientRect(); const clientX = e.touches ? e.touches[0].clientX : e.clientX; const v = Math.max(0, Math.min(1, (clientX - r.left) / r.width)); setProgress(v); if (v >= 0.99) setPlayerState("ended"); else if (playerState === "ended") setPlayerState("playing"); }; const onScrubDown = (e) => { draggingRef.current = true; setFromEvent(e); e.preventDefault(); }; useEffect(() => { const move = (e) => { if (draggingRef.current) setFromEvent(e); }; const up = () => { draggingRef.current = false; }; window.addEventListener("mousemove", move); window.addEventListener("mouseup", up); window.addEventListener("touchmove", move, { passive: false }); window.addEventListener("touchend", up); return () => { window.removeEventListener("mousemove", move); window.removeEventListener("mouseup", up); window.removeEventListener("touchmove", move); window.removeEventListener("touchend", up); }; }); // Reset progress when restarting/launching useEffect(() => { if (playerState === "launch") setProgress(0.38); }, [playerState]); const totalSec = 102; const curSec = Math.round(progress * totalSec); const fmt = (s) => `${String(Math.floor(s/60)).padStart(2,"0")}:${String(s%60).padStart(2,"0")}`; const pct = `${progress * 100}%`; return ( {playerState === "launch" && (
The Software-defined Train — the full story
1–2 minutes · concept video
setPlayerState("playing")}>▶ Launch video
)} {(playerState === "playing" || playerState === "ended") && ( {/* X close — top-right, returns to launch (and re-shows the menu) */} {/* Bottom controls — play/pause, draggable timeline, restart when ended */}
{/* Timeline — explicit standalone element so it's clearly visible */}
{ if (playerState === "ended") { setProgress(0); setPlayerState("playing"); } }}> {playerState === "ended" ? "▶" : "❚❚"}
{fmt(curSec)} / {fmt(totalSec)}
)}
); } Object.assign(window, { Screen4, Screen5, Screen6 });