// Live embedded mini-demos. Each mounts only if its root exists.
/* global React, ReactDOM */
const { useState, useEffect, useRef, useMemo } = React;
/* ─────────────── Copilot chat demo ─────────────── */
const copilotScript = [
{ who: 'user', text: 'Reschedule my 3pm with Leo to Thursday and brief the team.' },
{ who: 'agent', text: 'On it. Checking Leo\'s calendar and the team\'s availability.',
trace: ['calendar.read', 'messages.draft'] },
{ who: 'tool', text: 'Thursday 3–3:45pm works for everyone. Draft ready.' },
{ who: 'agent', text: 'Moved to Thursday 3pm. Sent a one-line heads-up to #product and a summary to Leo. Anything else?',
actions: ['Meeting moved', 'Slack posted', 'Summary emailed']
},
{ who: 'user', text: 'Also, how was my sleep last night?' },
{ who: 'agent', text: 'Solid. 7h 42m, high deep-sleep share. Resting HR trending –4 bpm week-over-week.',
trace: ['biosense.read', 'insights.compute']
},
];
function CopilotDemo() {
const [msgs, setMsgs] = useState([]);
const [typing, setTyping] = useState(false);
const bodyRef = useRef(null);
useEffect(() => {
let i = 0, cancelled = false;
async function run() {
while (!cancelled) {
const step = copilotScript[i % copilotScript.length];
if (step.who !== 'user') { setTyping(true); await wait(650); setTyping(false); }
if (!cancelled) setMsgs((m) => {
const next = [...m, { ...step, id: Date.now() + Math.random() }];
return next.slice(-6);
});
await wait(step.who === 'user' ? 1100 : 2600);
i++;
}
}
run();
return () => { cancelled = true; };
}, []);
useEffect(() => {
if (bodyRef.current) bodyRef.current.scrollTop = bodyRef.current.scrollHeight;
}, [msgs, typing]);
return (
{msgs.map(m => )}
{typing && }
);
}
function Bubble({ who, text, trace, actions }) {
if (who === 'user') {
return (
);
}
if (who === 'tool') {
return (
›{text}
);
}
return (
{text}
{trace && (
{trace.map(t => {t})}
)}
{actions && (
{actions.map(a => (
✓ {a}
))}
)}
);
}
function AgentDot() {
return ;
}
function Typing() {
return (
);
}
const wait = (ms) => new Promise(r => setTimeout(r, ms));
/* ─────────────── Heart rate sparkline ─────────────── */
function HRViz() {
const [data, setData] = useState(() => Array.from({length: 60}, (_, i) => 62 + Math.sin(i/3) * 6 + (Math.random()-0.5)*3));
const [hr, setHr] = useState(62);
useEffect(() => {
const id = setInterval(() => {
setData(d => {
const next = [...d.slice(1), d[d.length-1] + (Math.random()-0.5)*4];
const clamped = next.map(v => Math.max(52, Math.min(84, v)));
setHr(Math.round(clamped[clamped.length-1]));
const hrEl = document.getElementById('stat-hr');
if (hrEl) hrEl.innerHTML = `${Math.round(clamped[clamped.length-1])} bpm`;
return clamped;
});
}, 650);
return () => clearInterval(id);
}, []);
const w = 600, h = 200, pad = 8;
const min = 50, max = 86;
const pts = data.map((v, i) => {
const x = (i/(data.length-1)) * (w - pad*2) + pad;
const y = h - pad - ((v-min)/(max-min)) * (h - pad*2);
return [x, y];
});
const d = 'M' + pts.map(p => p.join(',')).join(' L');
const dArea = d + ` L${w-pad},${h-pad} L${pad},${h-pad} Z`;
return (
);
}
/* ─────────────── Fluid dashboard ─────────────── */
function FluidDashboard() {
return (
);
}
function SidePanel() {
const items = [
{icon:'◐', label:'Today', active:true},
{icon:'⊹', label:'Agents', badge:12},
{icon:'♡', label:'Health'},
{icon:'▢', label:'Spaces'},
{icon:'⎔', label:'Automations', badge:3},
];
return (
Mara K.
Connected · 4 devices
{items.map((it, i) => (
{it.icon}{it.label}
{it.badge && {it.badge}}
))}
VAI OS · v2.0.0
);
}
function MainPanel() {
const widgets = [
{ title:'Focus block', body:'Heads-down 9:30–11:00 · Product review', meta:'in 18 min', tone:'mint' },
{ title:'Leo moved to Thursday', body:'Calendar + Slack updated', meta:'Copilot · 2m ago', tone:'ok' },
{ title:'Readiness', body:'84 · high', meta:'BioSense Band', tone:'accent' },
{ title:'Invoice · Acme Co.', body:'Draft ready, amount reconciled', meta:'Finance agent', tone:'ok' },
{ title:'Travel brief', body:'Paris trip · weather, visa, hotel check-in ready', meta:'in 3 days', tone:'' },
{ title:'Sleep debt', body:'–28 min this week', meta:'trend: improving', tone:'' },
];
return (
Tuesday · April 28
Good morning, Mara.
3 agents active
{widgets.map((w, i) => (
{w.title}
{w.body}
{w.meta}
))}
);
}
function RightPanel() {
const [hr, setHr] = useState(64);
useEffect(() => {
const id = setInterval(() => setHr(h => Math.max(58, Math.min(72, h + (Math.random()-0.5)*2))), 900);
return () => clearInterval(id);
}, []);
return (
Suggestions
- Walk 8 min before your 11am call
- Wind-down at 22:30 — trending sleep debt
- Reply: Leo, 2 msgs waiting
Active agents
· scheduler
· finance
· health-copilot
);
}
function Pulse() {
return (
);
}
/* ─────────────── Mount ─────────────── */
const copilotRoot = document.getElementById('copilot-demo-body');
if (copilotRoot) ReactDOM.createRoot(copilotRoot).render();
const hrRoot = document.getElementById('hr-viz');
if (hrRoot) ReactDOM.createRoot(hrRoot).render();
const fluidRoot = document.getElementById('fluid-dashboard');
if (fluidRoot) ReactDOM.createRoot(fluidRoot).render();
// Expose HRViz for Health page
Object.assign(window, { HRViz, FluidDashboard, CopilotDemo });