WhistleBloom / frontend /index.html
ZhaoJingzi's picture
Upload 27 files
a1772f6 verified
Raw
History Blame Contribute Delete
6.69 kB
<main id="whistle-coach-app" class="whistle-app">
<header class="wc-header">
<div class="brand-lockup">
<div class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 64 64" role="img">
<path d="M15 36c7-10 18-15 33-12" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round"/>
<path d="M16 47c10-8 22-10 35-6" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" opacity=".58"/>
<circle cx="13" cy="29" r="5" fill="currentColor"/>
</svg>
</div>
<div>
<h1 style="color:#17213a">Whistle Coach <span>🌱</span></h1>
<p style="color:#52607d">Audio-first AI coach for your first whistle</p>
</div>
</div>
</header>
<section class="wc-layout" aria-label="Whistle Coach live practice">
<aside class="left-rail">
<section class="side-card flow-card">
<p class="card-kicker">🌱 BEGINNER FLOW</p>
<ol class="flow-list">
<li class="done"><span>1</span>Relax & posture</li>
<li class="done"><span>2</span>Round your lips</li>
<li class="done"><span>3</span>Small opening</li>
<li class="active"><span>4</span>Gentle airflow</li>
<li><span>5</span>Find tiny whistle</li>
<li><span>6</span>Hold a steady tone</li>
<li><span>7</span>Play a simple melody</li>
</ol>
<div class="steps-progress"><strong>4 / 7 steps</strong><span><i></i></span></div>
</section>
<section class="side-card journey-card">
<p class="card-kicker">🌱 YOUR WHISTLE JOURNEY</p>
<div class="journey-row">
<div class="progress-ring"><strong id="garden-growth">0%</strong></div>
<div>
<strong id="journey-title">You’re growing!</strong>
<p id="coach-message" aria-live="polite">Your flowers grow each time you hold a whistle.</p>
</div>
<div class="plant-pot" aria-hidden="true" data-growth-stage="seed">
<span class="plant-stem"></span>
<span class="plant-leaf plant-leaf-left"></span>
<span class="plant-leaf plant-leaf-right"></span>
<span class="plant-flower"></span>
<span class="plant-soil"></span>
</div>
</div>
</section>
</aside>
<section class="center-stage">
<article id="camera-stage" class="camera-card" data-feedback="red" tabindex="0" aria-label="Start live whistle practice">
<video id="practice-video" autoplay muted playsinline aria-label="Live webcam preview"></video>
<div id="camera-placeholder" class="camera-placeholder">
<div class="start-panel">
<div class="placeholder-face" aria-hidden="true"></div>
<strong>Start practice</strong>
<span>Put your mouth in the dotted oval, round your lips, then blow gently.</span>
<button id="center-start-practice" class="center-start-button" type="button">Start</button>
</div>
</div>
<canvas id="mouth-overlay" aria-hidden="true"></canvas>
<canvas id="garden-canvas" aria-hidden="true"></canvas>
<div class="live-guide" aria-hidden="true">
<strong>Put your mouth in the oval</strong>
<span>Round your lips, keep the opening small, then blow softly.</span>
</div>
<span id="session-state" class="live-chip" data-state="idle"><i></i><span class="session-copy">Ready</span></span>
<div id="coach-card" class="coach-bubble" data-state="idle"><span>🌱</span><strong id="hero-feedback">Ready for live practice</strong></div>
<div id="permission-note" class="permission-note">Camera and microphone stay in your browser.</div>
</article>
</section>
<aside class="right-rail">
<section class="listening-panel">
<div class="panel-heading"><span>▮▮</span><div><strong>AI LISTENING PANEL</strong><p>Audio is the core signal</p></div></div>
<section id="airflow-indicator" class="indicator-card green" data-state="red">
<div class="indicator-topline"><div class="indicator-name"><span>Airflow</span></div><strong class="indicator-score"><span>0</span><small>/100</small></strong></div>
<div class="score-track"><span class="score-fill"></span></div>
<p class="indicator-detail">Waiting for microphone</p>
</section>
<section id="whistle-indicator" class="indicator-card orange" data-state="red">
<div class="indicator-topline"><div class="indicator-name"><span>Whistle confidence (AST)</span></div><strong class="indicator-score"><span>0</span><small>/100</small></strong></div>
<div class="score-track"><span class="score-fill"></span></div>
<p class="indicator-detail">MIT AST listens for whistle-like sound.</p>
</section>
<section id="tone-indicator" class="indicator-card purple" data-state="red">
<div class="indicator-topline"><div class="indicator-name"><span>Pitch detected (F0)</span></div><strong class="indicator-score"><span>0</span><small></small></strong></div>
<div class="score-track"><span class="score-fill"></span></div>
<p class="indicator-detail">librosa.pyin waits for F0.</p>
</section>
<section id="stability-indicator" class="indicator-card blue" data-state="red">
<div class="indicator-topline"><div class="indicator-name"><span>Stability</span></div><strong class="indicator-score"><span>0</span><small>/100</small></strong></div>
<div class="score-track"><span class="score-fill"></span></div>
<p class="indicator-detail">Keep airflow steady.</p>
</section>
<p id="technical-status" class="technical-status">Detection loads when live practice begins.</p>
</section>
</aside>
</section>
<section id="mouth-indicator" class="indicator-card hidden-meter" data-state="red" aria-hidden="true">
<div class="indicator-topline"><div class="indicator-name"><span>Mouth shape</span></div><strong class="indicator-score"><span>0</span><small>/100</small></strong></div>
<div class="score-track"><span class="score-fill"></span></div>
<p class="indicator-detail">Waiting for a face</p>
</section>
<code id="practice-state-json" hidden>{"state":"idle"}</code>
<ol id="coach-trace-list" hidden></ol>
<span id="garden-growth-stage" hidden>0%</span>
<span id="garden-growth-fill" hidden></span>
<span id="garden-plants" hidden>0</span>
<span id="garden-streak" hidden>0.0</span>
</main>