reachy_mini_minder / index.html
Boopster's picture
feat: Introduce voice-guided onboarding demo with new screenshot styling and enhance ConfirmationCard UI.
8a22e30
Raw
History Blame Contribute Delete
12 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Reachy Mini Minder — Voice-First Care Companion</title>
<meta
name="description"
content="An empathy-driven, voice-first care companion for Reachy Mini, helping users log medication and track headaches through natural conversation."
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:wght@400;700&family=Poppins:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<!-- Hero -->
<header class="hero-panel">
<div class="hero-content">
<div class="hero-text">
<div class="pill">
<i data-lucide="bot" class="pill-icon"></i> Reachy Mini App
</div>
<h1>Reachy Mini<br />Minder</h1>
<p class="subtitle">
A voice-first care companion for Reachy Mini — helping users log
medication, track headaches, and manage daily wellness through
natural conversation.
</p>
<div class="hero-actions">
<a href="#features" class="btn-primary"
><i data-lucide="sparkles" class="btn-icon"></i> Explore
Features</a
>
<a href="#demos" class="btn-secondary"
><i data-lucide="play-circle" class="btn-icon"></i> Watch
Demos</a
>
</div>
</div>
<div class="hero-video">
<div class="demo-placeholder hero-demo">
<div class="demo-play">
<i data-lucide="play" class="demo-play-icon"></i>
</div>
<div class="demo-duration">1:30</div>
<div class="demo-badge">Coming Soon</div>
</div>
<p class="hero-video-caption">
Quick overview of Reachy Mini Minder
</p>
</div>
</div>
</header>
<!-- Core Features -->
<section class="panel" id="features">
<div class="panel-heading">
<p class="eyebrow">Core Features</p>
<h2>What It Does</h2>
</div>
<div class="feature-grid">
<div class="feature-card">
<div class="feature-icon cyan"><i data-lucide="mic"></i></div>
<h3>Voice-First Interaction</h3>
<p>
Speak naturally to log medications, report symptoms, and get
wellness check-ins via OpenAI Realtime API.
</p>
</div>
<div class="feature-card">
<div class="feature-icon pink"><i data-lucide="pill"></i></div>
<h3>Medication Tracking</h3>
<p>
Log doses, get gentle check-ins, and review your history — all
through conversation.
</p>
</div>
<div class="feature-card">
<div class="feature-icon purple"><i data-lucide="brain"></i></div>
<h3>Headache Journal</h3>
<p>Track severity, triggers, and duration through conversation.</p>
</div>
<div class="feature-card">
<div class="feature-icon cyan">
<i data-lucide="layout-dashboard"></i>
</div>
<h3>Live Dashboard</h3>
<p>
A React bento-grid UI showing medication schedules, headache
trends, and session summaries in real time.
</p>
</div>
<div class="feature-card">
<div class="feature-icon pink">
<i data-lucide="heart-handshake"></i>
</div>
<h3>Dignity-First Design</h3>
<p>
Supportive, never patronising. Health records stay on your device;
voice is processed via OpenAI with your consent.
</p>
</div>
<div class="feature-card">
<div class="feature-icon purple">
<i data-lucide="sparkles"></i>
</div>
<h3>Generative UI</h3>
<p>
Say "I have a headache" and a structured medical form fills in
field-by-field through conversation — zero taps, zero navigation.
23 components the AI invokes by voice.
</p>
</div>
</div>
</section>
<!-- Video Demos -->
<section class="panel" id="demos">
<div class="panel-heading">
<p class="eyebrow">Demos</p>
<h2>See It in Action</h2>
</div>
<div class="demo-grid">
<div class="demo-card">
<div class="demo-placeholder">
<div class="demo-play">
<i data-lucide="play" class="demo-play-icon"></i>
</div>
<div class="demo-duration">2:30</div>
<div class="demo-badge">Coming Soon</div>
</div>
<div class="demo-info">
<h3>Voice Conversation & Medication Logging</h3>
<p>
A full session showing wakeword activation, natural
conversation, and medication dose logging with real-time
dashboard updates.
</p>
</div>
</div>
<div class="demo-card">
<div class="demo-placeholder">
<div class="demo-play">
<i data-lucide="play" class="demo-play-icon"></i>
</div>
<div class="demo-duration">1:45</div>
<div class="demo-badge">Coming Soon</div>
</div>
<div class="demo-info">
<h3>Headache Tracking & Generative UI</h3>
<p>
Voice-driven clinical capture: say "I have a headache" and watch
intensity, triggers, and medication fields fill in progressively
as the conversation happens.
</p>
</div>
</div>
<div class="demo-card">
<div class="demo-screenshot-single">
<div class="screenshot-frame">
<img
src="frontend/public/reachy-mini-minder-onboarding-completed.png"
alt="Onboarding — All steps completed"
loading="lazy"
/>
</div>
</div>
<div class="demo-info">
<h3>Voice-Guided Onboarding</h3>
<p>
Five-step setup — name, medications, and caregiver contacts —
guided entirely by voice. The GenUI progress tracker updates
in real time as each step completes.
</p>
</div>
</div>
</div>
</section>
<!-- Architecture -->
<section class="panel">
<div class="panel-heading">
<p class="eyebrow">Architecture</p>
<h2>How It Works</h2>
</div>
<div class="arch-grid">
<div class="arch-card">
<div class="feature-icon cyan"><i data-lucide="monitor"></i></div>
<p class="arch-label">Frontend</p>
<p class="arch-value">React + Next.js</p>
<p class="arch-detail">
Real-time dashboard with WebSocket event bridge for instant UI
updates.
</p>
</div>
<div class="arch-card">
<div class="feature-icon pink"><i data-lucide="server"></i></div>
<p class="arch-label">Backend</p>
<p class="arch-value">LangGraph + FastAPI</p>
<p class="arch-detail">
Agent orchestration with tool-calling, session management, and
data persistence.
</p>
</div>
<div class="arch-card">
<div class="feature-icon purple"><i data-lucide="mic-2"></i></div>
<p class="arch-label">Voice</p>
<p class="arch-value">OpenAI Realtime API</p>
<p class="arch-detail">
Low-latency voice conversations with wakeword detection and VAD.
</p>
</div>
<div class="arch-card">
<div class="feature-icon cyan"><i data-lucide="cpu"></i></div>
<p class="arch-label">Robot</p>
<p class="arch-value">Reachy Mini SDK</p>
<p class="arch-detail">
Audio-reactive movement, head tracking, and expressive antenna
control.
</p>
</div>
</div>
</section>
<!-- Documentation Tabs -->
<section class="panel">
<div class="panel-heading">
<p class="eyebrow">Documentation</p>
<h2>Learn More</h2>
</div>
<div class="tabs" role="tablist">
<button
class="tab active"
role="tab"
aria-selected="true"
data-tab="readme"
>
README
</button>
<button
class="tab"
role="tab"
aria-selected="false"
data-tab="quickstart"
>
Quick Start
</button>
<button
class="tab"
role="tab"
aria-selected="false"
data-tab="dignity"
>
Dignity-First
</button>
<button
class="tab"
role="tab"
aria-selected="false"
data-tab="design"
>
Design System
</button>
</div>
<div class="tab-content" id="tab-content">
<div class="tab-loading">Loading documentation…</div>
</div>
</section>
<footer class="footer">
<p>
Built with <i data-lucide="heart" class="footer-heart"></i> for
<a href="https://www.pollen-robotics.com/" class="link"
>Reachy Mini</a
>
</p>
</footer>
</div>
<script>
const TAB_FILES = {
readme: "README.md",
quickstart: "documentation/quickstart.md",
dignity: "documentation/dignity_first_design_principles.md",
design: "documentation/design_system.md",
};
const cache = {};
const contentEl = document.getElementById("tab-content");
async function loadTab(tabId) {
if (cache[tabId]) {
contentEl.innerHTML = cache[tabId];
return;
}
contentEl.innerHTML = '<div class="tab-loading">Loading…</div>';
try {
const res = await fetch(TAB_FILES[tabId]);
if (!res.ok) throw new Error(res.statusText);
let md = await res.text();
md = md.replace(/^---[\s\S]*?---\s*/, "");
const html = marked.parse(md);
cache[tabId] = '<div class="md-body">' + html + "</div>";
contentEl.innerHTML = cache[tabId];
} catch (e) {
contentEl.innerHTML =
'<div class="tab-error">Could not load this document.</div>';
}
}
document.querySelectorAll(".tab").forEach((btn) => {
btn.addEventListener("click", () => {
document.querySelectorAll(".tab").forEach((t) => {
t.classList.remove("active");
t.setAttribute("aria-selected", "false");
});
btn.classList.add("active");
btn.setAttribute("aria-selected", "true");
loadTab(btn.dataset.tab);
});
});
loadTab("readme");
lucide.createIcons();
</script>
</body>
</html>