reachy_mini_bookreader / index.html.save
chitrark's picture
Sync local changes
b21fd1a
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ReadingBuddy โ€ข Reachy Mini BookReader</title>
<style>
:root{
--bg0:#0b1020;
--bg1:#0f172a;
--card:rgba(255,255,255,.06);
--card2:rgba(255,255,255,.08);
--stroke:rgba(255,255,255,.10);
--text:#e5e7eb;
--muted:#a3aab8;
--muted2:#b6becc;
--brand:#818cf8; /* indigo */
--brand2:#22c55e; /* green */
--warn:#f59e0b; /* amber */
--shadow: 0 20px 60px rgba(0,0,0,.35);
--radius: 18px;
}
*{ box-sizing:border-box; }
html,body{ height:100%; }
body{
margin:0;
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji","Segoe UI Emoji";
color:var(--text);
background:
radial-gradient(1200px 600px at 15% 0%, rgba(129,140,248,.25), transparent 60%),
radial-gradient(900px 500px at 85% 10%, rgba(34,197,94,.18), transparent 55%),
radial-gradient(700px 450px at 50% 95%, rgba(245,158,11,.16), transparent 55%),
linear-gradient(180deg, var(--bg0), var(--bg1));
line-height:1.6;
}
a{ color:#c7d2fe; text-decoration:none; }
a:hover{ text-decoration:underline; }
.container{
max-width: 980px;
margin: 0 auto;
padding: 28px 16px 64px;
}
/* Top mini-nav */
.topbar{
position: sticky;
top: 0;
z-index: 10;
margin: -12px 0 18px;
padding: 10px 0;
backdrop-filter: blur(10px);
background: linear-gradient(180deg, rgba(11,16,32,.72), rgba(11,16,32,.35));
border-bottom: 1px solid rgba(255,255,255,.06);
}
.topbar-inner{
display:flex;
align-items:center;
justify-content:space-between;
gap:12px;
max-width: 980px;
margin: 0 auto;
padding: 0 16px;
}
.brandline{
display:flex;
align-items:center;
gap:10px;
min-width: 200px;
}
.logo{
width:34px;
height:34px;
border-radius:12px;
background:
radial-gradient(circle at 30% 30%, rgba(129,140,248,.9), rgba(129,140,248,.25) 55%, transparent 60%),
radial-gradient(circle at 70% 70%, rgba(34,197,94,.65), rgba(34,197,94,.15) 58%, transparent 62%),
rgba(255,255,255,.06);
border: 1px solid rgba(255,255,255,.14);
box-shadow: 0 10px 24px rgba(0,0,0,.25);
display:grid;
place-items:center;
font-size: 16px;
}
.brandtext{
display:flex;
flex-direction:column;
line-height:1.15;
}
.brandtext strong{ font-size: 0.95rem; letter-spacing:.2px; }
.brandtext span{ font-size: 0.78rem; color: var(--muted); }
.navlinks{
display:flex;
flex-wrap:wrap;
gap:8px;
justify-content:flex-end;
}
.chiplink{
display:inline-flex;
align-items:center;
gap:6px;
padding: 7px 10px;
border-radius: 999px;
background: rgba(255,255,255,.06);
border: 1px solid rgba(255,255,255,.10);
color: var(--text);
font-size: 0.85rem;
white-space:nowrap;
}
.chiplink:hover{
background: rgba(255,255,255,.09);
text-decoration:none;
}
/* Hero */
header.hero{
margin-top: 14px;
padding: 22px 22px;
border-radius: var(--radius);
background: linear-gradient(135deg, rgba(255,255,255,.08), rgba(255,255,255,.03));
border: 1px solid rgba(255,255,255,.12);
box-shadow: var(--shadow);
overflow:hidden;
position:relative;
}
header.hero:before{
content:"";
position:absolute;
inset:-2px;
background:
radial-gradient(600px 200px at 18% 10%, rgba(129,140,248,.18), transparent 65%),
radial-gradient(500px 220px at 82% 0%, rgba(34,197,94,.16), transparent 68%);
pointer-events:none;
}
.hero-inner{
position:relative;
display:grid;
grid-template-columns: 1.2fr 0.8fr;
gap: 18px;
align-items:center;
}
@media (max-width: 860px){
.hero-inner{ grid-template-columns: 1fr; }
}
.badge{
display:inline-flex;
gap:8px;
align-items:center;
padding: 6px 10px;
border-radius: 999px;
background: rgba(129,140,248,.14);
border: 1px solid rgba(129,140,248,.26);
color: #e0e7ff;
font-size: 0.85rem;
width: fit-content;
}
h1{
margin: 10px 0 8px;
font-size: 2.25rem;
line-height: 1.15;
letter-spacing: -0.3px;
}
.sub{
margin: 0;
color: var(--muted2);
max-width: 62ch;
}
.hero-actions{
display:flex;
flex-direction:column;
gap:10px;
align-items:stretch;
justify-content:center;
}
.statrow{
display:grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.stat{
padding: 12px 12px;
border-radius: 14px;
background: rgba(255,255,255,.06);
border: 1px solid rgba(255,255,255,.10);
}
.stat .k{ color: var(--muted); font-size:.78rem; }
.stat .v{ font-size: 0.95rem; margin-top: 3px; }
.btnrow{
display:flex;
gap:10px;
flex-wrap:wrap;
}
.btn{
display:inline-flex;
align-items:center;
justify-content:center;
gap:8px;
padding: 10px 12px;
border-radius: 14px;
border: 1px solid rgba(255,255,255,.14);
background: rgba(255,255,255,.08);
color: var(--text);
font-weight: 600;
font-size: 0.92rem;
cursor: default;
user-select:none;
}
.btn.primary{
background: linear-gradient(135deg, rgba(129,140,248,.95), rgba(99,102,241,.70));
border: 1px solid rgba(129,140,248,.55);
color: #0b1020;
}
.btn small{ font-weight: 500; opacity:.9; }
/* Sections grid */
.grid{
display:grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
margin-top: 14px;
}
@media (max-width: 860px){
.grid{ grid-template-columns: 1fr; }
}
.card{
padding: 18px 18px;
border-radius: var(--radius);
background: var(--card);
border: 1px solid var(--stroke);
box-shadow: 0 10px 30px rgba(0,0,0,.22);
}
.card.full{ grid-column: 1 / -1; }
.card h2{
margin: 0 0 10px;
font-size: 1.2rem;
letter-spacing:-0.2px;
display:flex;
gap:8px;
align-items:center;
}
.card p{ margin: 0 0 10px; color: var(--muted2); }
.card p:last-child{ margin-bottom:0; }
.list{
margin: 10px 0 0;
padding: 0;
list-style:none;
display:grid;
gap: 10px;
}
.li{
display:flex;
gap:10px;
align-items:flex-start;
padding: 12px 12px;
border-radius: 14px;
background: rgba(255,255,255,.05);
border: 1px solid rgba(255,255,255,.09);
}
.li .icon{
width: 34px;
height: 34px;
border-radius: 12px;
display:grid;
place-items:center;
background: rgba(255,255,255,.06);
border: 1px solid rgba(255,255,255,.10);
flex: 0 0 auto;
margin-top: 1px;
}
.li strong{ display:block; margin-bottom: 2px; }
.li span{ color: var(--muted2); font-size: 0.95rem; }
.pills{
display:flex;
gap:8px;
flex-wrap:wrap;
margin-top: 10px;
}
.pill{
display:inline-flex;
align-items:center;
gap:6px;
padding: 6px 10px;
border-radius: 999px;
background: rgba(255,255,255,.06);
border: 1px solid rgba(255,255,255,.10);
font-size: 0.85rem;
color: var(--text);
}
.pill.good{ border-color: rgba(34,197,94,.35); background: rgba(34,197,94,.12); }
.pill.info{ border-color: rgba(129,140,248,.35); background: rgba(129,140,248,.12); }
.pill.warn{ border-color: rgba(245,158,11,.35); background: rgba(245,158,11,.12); }
code{
background: rgba(255,255,255,.08);
border: 1px solid rgba(255,255,255,.10);
padding: 2px 8px;
border-radius: 10px;
font-size: 0.92em;
color: #e9edff;
word-break: break-word;
}
ol{
margin: 10px 0 0;
padding-left: 1.1rem;
color: var(--muted2);
}
ol li{ margin: 8px 0; }
.callout{
margin-top: 12px;
padding: 12px 12px;
border-radius: 16px;
background: rgba(34,197,94,.10);
border: 1px solid rgba(34,197,94,.22);
color: #d1fae5;
}
.callout strong{ color:#ecfdf5; }
.kbd{
display:inline-block;
padding: 2px 8px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,.16);
background: rgba(255,255,255,.07);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 0.9em;
}
footer{
margin-top: 18px;
padding-top: 14px;
border-top: 1px solid rgba(255,255,255,.10);
color: var(--muted);
font-size: 0.92rem;
}
.fineprint{
display:flex;
flex-wrap:wrap;
gap:10px;
align-items:center;
justify-content:space-between;
}
.right{
opacity:.9;
}
</style>
</head>
<body>
<div class="topbar">
<div class="topbar-inner">
<div class="brandline">
<div class="logo">๐Ÿค–</div>
<div class="brandtext">
<strong>ReadingBuddy</strong>
<span>Reachy Mini BookReader</span>
</div>
</div>
<nav class="navlinks" aria-label="On-page navigation">
<a class="chiplink" href="#what">โœจ What it does</a>
<a class="chiplink" href="#install">๐Ÿš€ Install</a>
<a class="chiplink" href="#session">๐ŸŽฎ Session</a>
<a class="chiplink" href="#reqs">๐Ÿ“ฆ Requirements</a>
</nav>
</div>
</div>
<main class="container">
<header class="hero">
<div class="hero-inner">
<div>
<div class="badge">๐Ÿค–๐Ÿ“š Reachy Mini App โ€ข Kid-friendly reading companion</div>
<h1>ReadingBuddy</h1>
<p class="sub">
Turn your Reachy Mini into a book-reading buddy with fun voices, page memory,
and a simple camera-to-reading flow that kids can actually use.
</p>
<div class="pills" style="margin-top:14px;">
<span class="pill info">๐Ÿ“ธ OCR from camera</span>
<span class="pill info">๐ŸŽญ Character voices</span>
<span class="pill good">๐Ÿง  Resume by book</span>
<span class="pill warn">๐Ÿ”Š Hybrid TTS</span>
</div>
</div>
<div class="hero-actions" aria-label="Quick overview">
<div class="statrow">
<div class="stat">
<div class="k">Voices</div>
<div class="v">Tech Storyteller โ€ข Princess โ€ข Superhero โ€ข Robot Hero</div>
</div>
<div class="stat">
<div class="k">Best for</div>
<div class="v">Picture books + short pages kids follow along</div>
</div>
</div>
<div class="btnrow">
<div class="btn primary">โœ… Designed for demos <small>(fast + reliable)</small></div>
<div class="btn">๐Ÿงฉ Works with dashboard install</div>
</div>
</div>
</div>
</header>
<section id="what" class="grid" style="margin-top:16px;">
<div class="card full">
<h2>โœจ What ReadingBuddy does</h2>
<p>
<strong>ReadingBuddy turns your Reachy Mini into a book-reading companion.</strong>
Put a book in front of Reachy, choose a voice, capture a page, confirm the photo, and it reads out loud โ€”
while remembering where you stopped so kids can resume next time.
</p>
</div>
<div class="card">
<h2>Core features</h2>
<ul class="list">
<li class="li">
<div class="icon">๐Ÿ“ธ</div>
<div><strong>Smart OCR</strong><span>Capture a page from Reachyโ€™s camera and extract readable text.</span></div>
</li>
<li class="li">
<div class="icon">๐ŸŽญ</div>
<div><strong>4 character voices</strong><span>Tech Storyteller, Princess, Superhero, Robot Hero.</span></div>
</li>
<li class="li">
<div class="icon">๐Ÿง </div>
<div><strong>Page memory</strong><span>Saves your place per book for easy โ€œresumeโ€.</span></div>
</li>
</ul>
</div>
<div class="card">
<h2>Kid-friendly flow</h2>
<ul class="list">
<li class="li">
<div class="icon">โœ…</div>
<div><strong>Preview + confirm</strong><span>Kids can confirm the photo before OCR/reading starts.</span></div>
</li>
<li class="li">
<div class="icon">๐Ÿ“š</div>
<div><strong>Built-in stories</strong><span>Read preloaded public-domain stories without a camera.</span></div>
</li>
<li class="li">
<div class="icon">๐ŸŽฎ</div>
<div><strong>Simple controls</strong><span>Read, Retake, Next Page + Read, Again, Stop, hold-to-talk.</span></div>
</li>
</ul>
</div>
</section>
<section id="install" class="grid">
<div class="card full">
<h2>๐Ÿš€ How to install on Reachy Mini</h2>
<ol>
<li>Start the daemon (wireless version) and open the dashboard at <code>http://REACHY_MINI_IP:8000</code>.</li>
<li>Click <strong>Install from Hugging Face</strong>.</li>
<li>Search for <strong><code>reachy_mini_bookreader</code></strong> and click <strong>Install</strong>.</li>
<li>Open <strong>Applications</strong> โ†’ <strong>ReadingBuddy / BookReader</strong> โ†’ <strong>Run</strong>.</li>
<li>Click the <strong>โš™๏ธ</strong> settings icon on the app tile to open the full web UI.</li>
</ol>
<p style="margin-top:10px;">
Prefer CLI? You can publish/install via <span class="kbd">reachy-mini-app-assistant</span>.
</p>
</div>
</section>
<section id="session" class="grid">
<div class="card full">
<h2>๐ŸŽฎ How a reading session works</h2>
<ol>
<li>Enter a <strong>book title</strong> + page number (or resume saved progress).</li>
<li>Select a <strong>voice</strong> (optional: press <strong>Test Voice</strong>).</li>
<li>Press <strong>Read From Camera</strong> and hold the page steady in front of Reachy.</li>
<li>Confirm the captured photo in the preview modal.</li>
<li>Reachy runs OCR and reads the page aloud.</li>
<li>Use controls: <span class="pill info">Read</span> <span class="pill info">Retake</span> <span class="pill good">Next page</span> <span class="pill info">Again</span> <span class="pill warn">Stop</span></li>
</ol>
<div class="callout">
<strong>Tip:</strong> For glossy pages or low light, move the book slightly closer and keep it flat.
A tiny angle change can make OCR much cleaner.
</div>
</div>
</section>
<section id="reqs" class="grid">
<div class="card">
<h2>๐Ÿ“ฆ Requirements</h2>
<ul class="list">
<li class="li">
<div class="icon">๐Ÿค–</div>
<div><strong>Reachy Mini</strong><span>Wireless version recommended, with camera + audio working.</span></div>
</li>
<li class="li">
<div class="icon">๐Ÿงฉ</div>
<div><strong>SDK + dashboard</strong><span><code>reachy-mini</code> version โ‰ฅ <strong>1.2.13</strong>.</span></div>
</li>
<li class="li">
<div class="icon">๐Ÿ”Š</div>
<div><strong>Hybrid TTS</strong><span>Uses ElevenLabs when available, otherwise espeak-ng fallback.</span></div>
</li>
</ul>
</div>
<div class="card">
<h2>๐Ÿ” Optional env vars</h2>
<p>Set these if you want premium voice quality:</p>
<div class="pills">
<span class="pill warn"><strong>ELEVENLABS_API_KEY</strong></span>
</div>
<p style="margin-top:10px;">
If not set, the app automatically falls back to free TTS (so your demo still works).
</p>
</div>
</section>
<footer>
<div class="fineprint">
<div>
This is a Reachy Mini app โ€” it requires the robot hardware to run.
</div>
<div class="right">
Learn more: <a href="https://www.pollen-robotics.com/reachy-mini/" target="_blank" rel="noreferrer">Pollen Robotics โ€ข Reachy Mini</a>
</div>
</div>
</footer>
</main>
</body>
</html>