Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/features/INTERACTIVE_DEMO_PARITY_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -550,3 +550,7 @@ are consistent. Nothing is persisted: a reload resets the watch.
**When you change a watch view, mirror it here.** The Swift ↔ JS pairs above
are the map; the strings are copied verbatim from `HomeView.swift`,
`MatchTrackingStatus.swift`, `SettingsCopy.swift` and `WalkthroughFixtures.swift`.

## Page modes (try.html)

`try.html` is one watch with a three-way mode switch (`S.setMode` in `watch-demo-app.js`): **Score only** (Track point outcome off), **Score + stats** (on) and **Watch the guide** (opens the animated walkthrough). Intentionally skipped: Health (permission prompt and real sensors — HR, kcal, steps and compass are invented), the first-launch guide offer, and the iPhone side.
13 changes: 13 additions & 0 deletions docs/website/assets/watch-app.css
Original file line number Diff line number Diff line change
Expand Up @@ -477,3 +477,16 @@
.app-scroll.pad.det { padding-top: calc(59 * var(--pt)); }
.pbtn { text-align: left; justify-content: center; padding-left: calc(16 * var(--pt)); padding-right: calc(12 * var(--pt)); }
.pbtn .ic { margin-right: calc(2 * var(--pt)); }

/* ---- Mode switch above the watch (try.html) ---- */
.mode-tabs { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin: 0 auto 8px; }
.mode-tabs .util-btn { padding: 9px 16px; }
.mode-caption { margin: 0 auto 18px; max-width: 46ch; text-align: center; color: var(--muted); font-size: .88rem; line-height: 1.5; min-height: 2.6em; }
.demo-legend { margin: 18px auto 0; text-align: center; color: var(--muted); font-size: .88rem; line-height: 1.7; }
.demo-legend summary { cursor: pointer; margin-top: 6px; }
.demo-legend .kbd { display: inline-block; background: var(--glass-2); border: 1px solid var(--line); border-radius: 6px; padding: 1px 7px; font-size: .85em; font-weight: 700; color: var(--ink); }
.real-skipped { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; max-width: 760px; margin: 22px auto 0; text-align: left; }
.real-skipped > div { padding: 12px 16px; border-radius: 12px; border: 1px solid var(--line); background: var(--glass-2); font-size: .88rem; line-height: 1.55; color: var(--muted); }
.real-skipped strong { display: block; color: var(--ink); margin-bottom: 2px; }
.real-skipped .skipped { border-color: rgba(255,206,74,.3); background: rgba(255,206,74,.08); }
@media (max-width: 560px) { .real-skipped { grid-template-columns: 1fr; } }
40 changes: 40 additions & 0 deletions docs/website/assets/watch-demo-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@
shellEl.classList.toggle("is-playing", playing);
syncChrome();
api.refresh();
if (S.onRender) S.onRender();
if (!S.stack.length && !S.alert && S.afterRender) setTimeout(S.afterRender, 0);
}
function isNavTitle(top) { return !!top && top.id === "birthyear"; }
Expand Down Expand Up @@ -695,6 +696,45 @@
window.addEventListener("resize", setPt);
if (window.ResizeObserver) new ResizeObserver(setPt).observe(screenEl);

/* ---- Page-level mode switch (try.html): Score only / Score + stats / Guide.
One watch, so a switch parks nothing — it returns to a fresh Home. ---- */
var modeBtns = root.parentNode ? document.querySelectorAll("[data-mode]") : [];
function currentMode() {
var top = S.top();
if (top && top.id === "walkthrough") return "guide";
return S.settings.track ? "stats" : "score";
}
S.onRender = function () {
var m = currentMode();
Array.prototype.forEach.call(modeBtns, function (b) {
var on = b.getAttribute("data-mode") === m;
b.setAttribute("aria-pressed", on ? "true" : "false");
b.classList.toggle("active", on);
});
var cap = document.querySelector("[data-mode-caption]");
if (cap) cap.textContent = MODE_CAPTIONS[m];
};
var MODE_CAPTIONS = {
score: "Just the score. Tracking is off, as it is by default on the real watch.",
stats: "Each point ends with a quick tap: Double Fault, Winner, Forced or Unforced. Live stats build as you play.",
guide: "The animated Guide, running itself. Use Previous and Next to move through it."
};
S.setMode = function (mode) {
api.clear();
S.stack.length = 0; S.alert = null;
S.matchPhase = "warmup"; S.liveId = null; S.headingLocked = false;
if (mode !== "guide") {
S.settings.track = mode === "stats";
api.configure({ tracking: S.settings.track });
render();
} else {
push({ id: "walkthrough", offer: false });
}
};
Array.prototype.forEach.call(modeBtns, function (b) {
b.addEventListener("click", function () { S.setMode(b.getAttribute("data-mode")); });
});

S.boot = function () {
setPt();
applyTheme();
Expand Down
61 changes: 27 additions & 34 deletions docs/website/try.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="index,follow">
<meta name="theme-color" content="#080b0a">
<title>Try DeuceMate — the Apple Watch app in your browser</title>
<meta name="description" content="A free, interactive replica of the DeuceMate Apple Watch app: home screen, match setup, settings, past matches, the animated guide and the live scorer across all six match formats — no install required.">
<title>Try DeuceMate — a simulated Apple Watch demo</title>
<meta name="description" content="A simulated browser demo that mirrors the DeuceMate Apple Watch app: match setup, scoring with or without point tracking, live stats, past matches and the animated guide. Health sensors and iPhone features are skipped.">

<meta property="og:type" content="website">
<meta property="og:title" content="Try DeuceMate in your browser">
<meta property="og:description" content="Try the whole DeuceMate Apple Watch app right in your browser — home, setup, settings, history, the guide and the live scorer.">
<meta property="og:description" content="A simulated browser demo that mirrors the DeuceMate Apple Watch app — score a match, with or without point tracking, or watch the guide.">
<meta property="og:image" content="assets/deucemate-icon.png">
<meta property="og:url" content="https://emrahman.github.io/DeuceMate/try.html">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Try DeuceMate in your browser">
<meta name="twitter:description" content="Try the whole DeuceMate Apple Watch app in your browser — home, setup, settings, match history, the guide and the live scorer.">
<meta name="twitter:description" content="A simulated browser demo that mirrors the DeuceMate Apple Watch app — score a match, with or without point tracking, or watch the guide.">
<meta name="twitter:image" content="assets/deucemate-icon.png">

<link rel="icon" type="image/png" href="assets/deucemate-logo.png">
Expand Down Expand Up @@ -58,27 +58,30 @@
<main>
<section style="padding-top:56px;padding-bottom:24px;">
<div class="wrap" style="text-align:center;">
<span class="eyebrow">🎾 Interactive demo · no install</span>
<span class="eyebrow">🎾 Simulated browser demo</span>
<h1 class="title" style="font-size:clamp(2rem,5vw,3rem);font-weight:850;max-width:18ch;margin:14px auto 0;">
Try the watch app <span class="grad-text">right here</span>
</h1>
<p class="lede" style="max-width:56ch;margin:16px auto 0;">
A replica of the Apple&nbsp;Watch app, start to finish: the home screen, match setup,
Settings, Past Matches and the animated Guide — plus the same scoring logic as the
watch, with full server rotation, point-by-point categorisation and live stats.
Heart rate, calories and steps are made up; everything else works.
</p>
<p class="sim-note">
⚠️ This is a <strong>simulated browser demo</strong> to give you a feel for how scoring works —
it is <strong>not the actual product</strong>. The real DeuceMate is a native Apple&nbsp;Watch
&amp; iPhone app with live watch&nbsp;↔&nbsp;phone sync, full match stats, heart-rate insights
and one-tap AI coaching.
A browser simulation that mirrors the Apple&nbsp;Watch app: same scoring rules,
match setup, Settings, Past Matches and Guide.
</p>
<div class="real-skipped">
<div><strong>Works like the app</strong>All six formats, server rotation, changeovers, point categories, live stats, Past Matches, the Guide.</div>
<div class="skipped"><strong>Skipped here</strong>Health: heart rate, calories, steps and compass are invented. Also the first-launch guide offer, and the iPhone side (sync, archive, announcements, AI&nbsp;Coach).</div>
</div>
</div>
</section>

<section style="padding-top:8px;">
<div class="wrap">
<div class="mode-tabs" role="group" aria-label="Demo mode">
<button type="button" class="util-btn" data-mode="score" aria-pressed="true">Score only</button>
<button type="button" class="util-btn" data-mode="stats" aria-pressed="false">Score + stats</button>
<button type="button" class="util-btn" data-mode="guide" aria-pressed="false">Watch the guide</button>
</div>
<p class="mode-caption" data-mode-caption aria-live="polite"></p>

<div id="watch-demo" data-keyboard data-app>
<div class="demo-wrap">
<div data-play>
Expand Down Expand Up @@ -189,28 +192,18 @@ <h1 class="title" style="font-size:clamp(2rem,5vw,3rem);font-weight:850;max-widt
</div>
</div>

<p class="demo-hint">
This is the whole watch app, not just the scoreboard: the <strong>home screen</strong>
(Start Match, match setup, tracking strip), <strong>Settings</strong>,
<strong>Past Matches</strong> and the <strong>Guide</strong> with its animated walkthrough.
Click or tap the buttons on the watch face. Heart rate, calories and steps are
invented — a browser has no sensors.<br>
<strong>In a match, swipe the watch face</strong> (drag with the mouse or your finger):
<strong>up</strong> wins a point, <strong>down</strong> loses one, <strong>left</strong> undoes,
<strong>right</strong> opens Live Stats. <strong>Double-tap the scoreboard</strong> to flag a
2nd serve.<br>
As on the real watch, <strong>Track point outcome is off until you turn it on in Settings</strong>
— then each point ends with the Double&nbsp;Fault / Winner / Forced / Unforced tap-through and
live stats build as you play (Perpetual Points never tracks).<br>
Keyboard in a match: <span class="kbd">↑</span> win · <span class="kbd">↓</span> lose ·
<span class="kbd">U</span> undo · <span class="kbd">S</span> stats · <span class="kbd">2</span> 2nd serve.
</p>
<div class="demo-legend">
Swipe the watch face: <strong>↑</strong> win · <strong>↓</strong> lose · <strong>←</strong> undo · <strong>→</strong> stats · double-tap for 2nd serve
<details>
<summary>Keyboard shortcuts</summary>
<span class="kbd">↑</span> win · <span class="kbd">↓</span> lose · <span class="kbd">U</span> undo · <span class="kbd">S</span> stats · <span class="kbd">2</span> 2nd serve
</details>
</div>

<div class="cta-final" style="margin-top:44px;">
<span class="eyebrow">✅ Available now on the App Store</span>
<h2>Like it? Take it to the court.</h2>
<p>This demo is only the scorer. The real app adds live iPhone mirroring, spoken
announcements, 20+ match stats, heart-rate insights and one-tap AI&nbsp;coaching.</p>
<p>The real app adds live iPhone mirroring, 20+ match stats, heart-rate insights and one-tap AI&nbsp;coaching.</p>
<div class="hero-actions" style="margin-top:26px;">
<a class="btn btn-primary btn-lg" href="https://apps.apple.com/app/id6757105622" target="_blank" rel="noopener">
<span aria-hidden="true">↓</span> Download on the App&nbsp;Store
Expand Down Expand Up @@ -242,7 +235,7 @@ <h2>Like it? Take it to the court.</h2>
<a href="mailto:mail@ehsanrahman.com">Contact</a>
<a href="https://ehsanrahman.com" target="_blank" rel="noopener">ehsanrahman.com</a>
</nav>
<p class="fine">© 2026 Ehsan Rahman · This browser demo is for fun — the Apple Watch app is the real scorer. DeuceMate is not affiliated with Apple Inc.</p>
<p class="fine">© 2026 Ehsan Rahman · This browser demo is a simulation — the Apple Watch app is the real scorer. DeuceMate is not affiliated with Apple Inc.</p>
</div>
</footer>

Expand Down
Loading