Download index.html from Wearables/explorer: direct link, hf CLI and curl.
- Browser
- Download file 38.2 kB
-
https://huggingface.co/spaces/Wearables/explorer/resolve/main/index.html
- Command line
-
hf download hf://spaces/Wearables/explorer/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Wearables/explorer/resolve/main/index.html
38.2 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Wearables Explorer — Compare Smartwatches, Rings & Trackers</title> | |
| <meta | |
| name="description" | |
| content="Discover and compare selected wearables by features, pros, cons, compatibility and use case. An independent curated wearable explorer." | |
| /> | |
| <meta name="robots" content="index,follow" /> | |
| <meta name="theme-color" content="#0b1020" /> | |
| <meta property="og:title" content="Wearables Explorer" /> | |
| <meta | |
| property="og:description" | |
| content="Compare selected wearables: features, pros, cons and compatibility." | |
| /> | |
| <meta property="og:type" content="website" /> | |
| <meta property="og:image" content="wearables.png" /> | |
| <link rel="icon" href="wearables.png" /> | |
| <link rel="apple-touch-icon" href="wearables.png" /> | |
| <style> | |
| :root { | |
| --bg: #07101d; | |
| --bg-soft: #0b1525; | |
| --card: rgba(16, 28, 48, 0.78); | |
| --card-strong: #101c30; | |
| --line: rgba(255, 255, 255, 0.09); | |
| --text: #f4f7fb; | |
| --muted: #9daabc; | |
| --accent: #8c67ff; | |
| --accent-2: #2fc7a5; | |
| --accent-3: #6ea8ff; | |
| --good: #57d6a6; | |
| --bad: #ff8f9b; | |
| --shadow: 0 22px 70px rgba(0,0,0,.28); | |
| --radius: 22px; | |
| --radius-sm: 14px; | |
| --max: 1220px; | |
| } | |
| * { box-sizing: border-box; } | |
| html { scroll-behavior: smooth; } | |
| body { | |
| margin: 0; | |
| min-height: 100vh; | |
| background: | |
| radial-gradient(circle at 16% 0%, rgba(140,103,255,.18), transparent 34%), | |
| radial-gradient(circle at 86% 6%, rgba(47,199,165,.13), transparent 32%), | |
| linear-gradient(180deg, #07101d 0%, #08111f 55%, #07101d 100%); | |
| color: var(--text); | |
| font-family: | |
| Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, | |
| "Segoe UI", sans-serif; | |
| line-height: 1.55; | |
| } | |
| button, input, select { font: inherit; } | |
| a { color: inherit; } | |
| .shell { | |
| width: min(calc(100% - 32px), var(--max)); | |
| margin: 0 auto; | |
| } | |
| .topbar { | |
| position: sticky; | |
| top: 0; | |
| z-index: 30; | |
| backdrop-filter: blur(18px); | |
| background: rgba(7,16,29,.78); | |
| border-bottom: 1px solid var(--line); | |
| } | |
| .topbar-inner { | |
| min-height: 72px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 20px; | |
| } | |
| .brand { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| min-width: 0; | |
| } | |
| .brand img { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 12px; | |
| object-fit: cover; | |
| background: #111b2d; | |
| border: 1px solid var(--line); | |
| } | |
| .brand-title { | |
| font-weight: 780; | |
| letter-spacing: -.02em; | |
| } | |
| .brand-sub { | |
| color: var(--muted); | |
| font-size: .78rem; | |
| margin-top: -2px; | |
| } | |
| .status-pill { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 8px 11px; | |
| border: 1px solid var(--line); | |
| border-radius: 999px; | |
| color: #cbd5e1; | |
| background: rgba(255,255,255,.035); | |
| font-size: .78rem; | |
| white-space: nowrap; | |
| } | |
| .status-dot { | |
| width: 7px; | |
| height: 7px; | |
| background: var(--accent-2); | |
| border-radius: 50%; | |
| box-shadow: 0 0 0 5px rgba(47,199,165,.12); | |
| } | |
| .hero { | |
| padding: 76px 0 36px; | |
| display: grid; | |
| grid-template-columns: minmax(0, 1.35fr) minmax(280px, .65fr); | |
| gap: 44px; | |
| align-items: end; | |
| } | |
| .eyebrow { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 16px; | |
| padding: 7px 11px; | |
| border: 1px solid rgba(140,103,255,.24); | |
| border-radius: 999px; | |
| background: rgba(140,103,255,.09); | |
| color: #cfc3ff; | |
| font-size: .8rem; | |
| font-weight: 650; | |
| } | |
| h1 { | |
| margin: 0; | |
| max-width: 850px; | |
| font-size: clamp(2.45rem, 6vw, 5.2rem); | |
| line-height: .98; | |
| letter-spacing: -.06em; | |
| } | |
| .gradient { | |
| background: linear-gradient(90deg, #b59cff 0%, #7fb2ff 45%, #55d9b7 100%); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| } | |
| .hero p { | |
| max-width: 760px; | |
| margin: 24px 0 0; | |
| color: #b8c3d2; | |
| font-size: clamp(1rem, 2vw, 1.16rem); | |
| } | |
| .hero-note { | |
| padding: 20px; | |
| border: 1px solid var(--line); | |
| border-radius: var(--radius); | |
| background: linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.018)); | |
| box-shadow: var(--shadow); | |
| } | |
| .hero-note strong { | |
| display: block; | |
| font-size: .95rem; | |
| margin-bottom: 8px; | |
| } | |
| .hero-note p { | |
| margin: 0; | |
| font-size: .86rem; | |
| color: var(--muted); | |
| } | |
| .stats { | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 10px; | |
| margin-top: 18px; | |
| } | |
| .stat { | |
| padding: 13px; | |
| border: 1px solid var(--line); | |
| border-radius: 14px; | |
| background: rgba(0,0,0,.12); | |
| } | |
| .stat b { | |
| display: block; | |
| font-size: 1.08rem; | |
| } | |
| .stat span { | |
| color: var(--muted); | |
| font-size: .72rem; | |
| } | |
| .controls-wrap { | |
| position: relative; | |
| z-index: 5; | |
| margin: 18px 0 28px; | |
| padding: 16px; | |
| border: 1px solid var(--line); | |
| border-radius: 20px; | |
| background: rgba(10,20,35,.8); | |
| backdrop-filter: blur(12px); | |
| } | |
| .controls { | |
| display: grid; | |
| grid-template-columns: minmax(220px, 1.5fr) minmax(160px, .7fr) minmax(160px, .7fr); | |
| gap: 10px; | |
| } | |
| .input, .select { | |
| width: 100%; | |
| min-height: 46px; | |
| border: 1px solid var(--line); | |
| border-radius: 13px; | |
| outline: none; | |
| background: rgba(255,255,255,.04); | |
| color: var(--text); | |
| padding: 0 14px; | |
| } | |
| .input:focus, .select:focus { | |
| border-color: rgba(140,103,255,.55); | |
| box-shadow: 0 0 0 4px rgba(140,103,255,.10); | |
| } | |
| .select option { | |
| background: #101c30; | |
| color: white; | |
| } | |
| .quick-filters { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| margin-top: 12px; | |
| } | |
| .chip { | |
| border: 1px solid var(--line); | |
| border-radius: 999px; | |
| background: rgba(255,255,255,.025); | |
| color: #c8d2df; | |
| padding: 8px 12px; | |
| cursor: pointer; | |
| transition: .18s ease; | |
| } | |
| .chip:hover, .chip.active { | |
| border-color: rgba(140,103,255,.42); | |
| background: rgba(140,103,255,.12); | |
| color: white; | |
| } | |
| .section-head { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: end; | |
| gap: 20px; | |
| margin: 34px 0 17px; | |
| } | |
| .section-head h2 { | |
| margin: 0; | |
| font-size: 1.55rem; | |
| letter-spacing: -.03em; | |
| } | |
| .section-head p { | |
| margin: 5px 0 0; | |
| color: var(--muted); | |
| font-size: .9rem; | |
| } | |
| #resultCount { | |
| color: var(--muted); | |
| font-size: .86rem; | |
| white-space: nowrap; | |
| } | |
| .grid { | |
| display: grid; | |
| grid-template-columns: repeat(3, minmax(0,1fr)); | |
| gap: 16px; | |
| padding-bottom: 100px; | |
| } | |
| .card { | |
| min-width: 0; | |
| display: flex; | |
| flex-direction: column; | |
| border: 1px solid var(--line); | |
| border-radius: var(--radius); | |
| overflow: hidden; | |
| background: | |
| linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.018)), | |
| var(--card); | |
| box-shadow: 0 12px 40px rgba(0,0,0,.13); | |
| transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease; | |
| } | |
| .card:hover { | |
| transform: translateY(-3px); | |
| border-color: rgba(255,255,255,.16); | |
| box-shadow: 0 18px 50px rgba(0,0,0,.23); | |
| } | |
| .card-top { | |
| padding: 20px 20px 16px; | |
| border-bottom: 1px solid var(--line); | |
| min-height: 174px; | |
| background: | |
| radial-gradient(circle at 88% 0%, var(--glow, rgba(140,103,255,.12)), transparent 42%); | |
| } | |
| .card-meta { | |
| display: flex; | |
| justify-content: space-between; | |
| gap: 10px; | |
| align-items: center; | |
| margin-bottom: 18px; | |
| } | |
| .brand-tag, .new-tag { | |
| font-size: .72rem; | |
| font-weight: 720; | |
| letter-spacing: .03em; | |
| text-transform: uppercase; | |
| color: #d6deea; | |
| } | |
| .new-tag { | |
| padding: 5px 8px; | |
| border-radius: 999px; | |
| color: #adf1dd; | |
| background: rgba(47,199,165,.10); | |
| border: 1px solid rgba(47,199,165,.18); | |
| } | |
| .device-name { | |
| margin: 0; | |
| font-size: 1.42rem; | |
| line-height: 1.14; | |
| letter-spacing: -.035em; | |
| } | |
| .device-type { | |
| margin: 8px 0 0; | |
| color: var(--muted); | |
| font-size: .85rem; | |
| } | |
| .card-body { | |
| display: flex; | |
| flex-direction: column; | |
| flex: 1; | |
| padding: 18px 20px 20px; | |
| } | |
| .summary { | |
| color: #c4cedb; | |
| font-size: .91rem; | |
| min-height: 68px; | |
| margin: 0 0 16px; | |
| } | |
| .keyline { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 8px; | |
| margin-bottom: 16px; | |
| } | |
| .key { | |
| padding: 10px; | |
| border-radius: 12px; | |
| background: rgba(255,255,255,.03); | |
| border: 1px solid var(--line); | |
| } | |
| .key span { | |
| display: block; | |
| color: var(--muted); | |
| font-size: .68rem; | |
| margin-bottom: 3px; | |
| } | |
| .key b { | |
| display: block; | |
| font-size: .8rem; | |
| line-height: 1.25; | |
| } | |
| .pc { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 10px; | |
| margin: 3px 0 18px; | |
| } | |
| .pc-title { | |
| font-size: .74rem; | |
| text-transform: uppercase; | |
| letter-spacing: .06em; | |
| font-weight: 760; | |
| margin-bottom: 7px; | |
| } | |
| .pros .pc-title { color: var(--good); } | |
| .cons .pc-title { color: var(--bad); } | |
| .pc ul { | |
| padding-left: 16px; | |
| margin: 0; | |
| color: #b9c3d0; | |
| font-size: .78rem; | |
| } | |
| .pc li + li { margin-top: 4px; } | |
| .card-actions { | |
| display: grid; | |
| grid-template-columns: 1fr auto; | |
| gap: 8px; | |
| margin-top: auto; | |
| } | |
| .btn { | |
| min-height: 42px; | |
| border: 1px solid var(--line); | |
| border-radius: 12px; | |
| padding: 0 13px; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| text-decoration: none; | |
| cursor: pointer; | |
| transition: .16s ease; | |
| background: rgba(255,255,255,.035); | |
| color: var(--text); | |
| font-weight: 650; | |
| font-size: .82rem; | |
| } | |
| .btn:hover { | |
| border-color: rgba(255,255,255,.22); | |
| background: rgba(255,255,255,.07); | |
| } | |
| .btn.primary { | |
| background: linear-gradient(135deg, rgba(140,103,255,.25), rgba(47,199,165,.14)); | |
| border-color: rgba(140,103,255,.35); | |
| } | |
| .btn.selected { | |
| background: rgba(47,199,165,.14); | |
| border-color: rgba(47,199,165,.38); | |
| color: #c9ffef; | |
| } | |
| .empty { | |
| grid-column: 1 / -1; | |
| padding: 60px 20px; | |
| text-align: center; | |
| color: var(--muted); | |
| border: 1px dashed var(--line); | |
| border-radius: var(--radius); | |
| } | |
| .compare-bar { | |
| position: fixed; | |
| z-index: 45; | |
| left: 50%; | |
| bottom: 18px; | |
| transform: translateX(-50%) translateY(140%); | |
| width: min(calc(100% - 28px), 760px); | |
| padding: 12px; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| border: 1px solid rgba(255,255,255,.13); | |
| border-radius: 18px; | |
| background: rgba(13,24,41,.94); | |
| backdrop-filter: blur(20px); | |
| box-shadow: 0 20px 70px rgba(0,0,0,.45); | |
| transition: transform .25s ease; | |
| } | |
| .compare-bar.show { | |
| transform: translateX(-50%) translateY(0); | |
| } | |
| .compare-info { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .compare-info b { | |
| display: block; | |
| font-size: .87rem; | |
| } | |
| .compare-info span { | |
| display: block; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| color: var(--muted); | |
| font-size: .74rem; | |
| } | |
| .overlay { | |
| position: fixed; | |
| z-index: 70; | |
| inset: 0; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 20px; | |
| background: rgba(1,5,12,.74); | |
| backdrop-filter: blur(10px); | |
| } | |
| .overlay.open { display: flex; } | |
| .modal { | |
| width: min(1120px, 100%); | |
| max-height: min(860px, 92vh); | |
| overflow: auto; | |
| background: #0b1627; | |
| border: 1px solid rgba(255,255,255,.12); | |
| border-radius: 24px; | |
| box-shadow: var(--shadow); | |
| } | |
| .modal-head { | |
| position: sticky; | |
| top: 0; | |
| z-index: 3; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| gap: 20px; | |
| padding: 18px 20px; | |
| background: rgba(11,22,39,.95); | |
| backdrop-filter: blur(15px); | |
| border-bottom: 1px solid var(--line); | |
| } | |
| .modal-head h3 { | |
| margin: 0; | |
| font-size: 1.18rem; | |
| } | |
| .icon-btn { | |
| width: 40px; | |
| height: 40px; | |
| border: 1px solid var(--line); | |
| border-radius: 12px; | |
| background: rgba(255,255,255,.04); | |
| color: white; | |
| cursor: pointer; | |
| } | |
| .table-wrap { | |
| overflow-x: auto; | |
| padding: 8px 20px 22px; | |
| } | |
| table { | |
| width: 100%; | |
| min-width: 760px; | |
| border-collapse: collapse; | |
| } | |
| th, td { | |
| border-bottom: 1px solid var(--line); | |
| padding: 15px 14px; | |
| vertical-align: top; | |
| text-align: left; | |
| font-size: .85rem; | |
| } | |
| th:first-child, td:first-child { | |
| width: 160px; | |
| color: var(--muted); | |
| font-weight: 600; | |
| } | |
| th { | |
| color: white; | |
| font-size: .92rem; | |
| } | |
| .footer { | |
| padding: 8px 0 54px; | |
| border-top: 1px solid var(--line); | |
| color: var(--muted); | |
| } | |
| .footer-grid { | |
| display: grid; | |
| grid-template-columns: 1.2fr .8fr; | |
| gap: 32px; | |
| padding-top: 28px; | |
| } | |
| .footer strong { | |
| color: #dbe4ef; | |
| } | |
| .footer p { | |
| margin: 8px 0 0; | |
| font-size: .82rem; | |
| } | |
| .footer a { | |
| color: #bdc9d8; | |
| text-underline-offset: 3px; | |
| } | |
| .tiny { | |
| margin-top: 22px ; | |
| color: #76869a; | |
| font-size: .74rem ; | |
| } | |
| @media (max-width: 980px) { | |
| .hero { | |
| grid-template-columns: 1fr; | |
| gap: 22px; | |
| padding-top: 54px; | |
| } | |
| .hero-note { max-width: 720px; } | |
| .grid { grid-template-columns: repeat(2, minmax(0,1fr)); } | |
| .controls { grid-template-columns: 1fr 1fr; } | |
| .controls .input { grid-column: 1 / -1; } | |
| } | |
| @media (max-width: 670px) { | |
| .shell { width: min(calc(100% - 20px), var(--max)); } | |
| .topbar-inner { min-height: 64px; } | |
| .brand-sub { display: none; } | |
| .status-pill { font-size: 0; padding: 9px; } | |
| .status-dot { margin: 0; } | |
| .hero { padding-top: 40px; } | |
| h1 { font-size: clamp(2.6rem, 14vw, 4.4rem); } | |
| .stats { grid-template-columns: 1fr; } | |
| .controls { grid-template-columns: 1fr; } | |
| .controls .input { grid-column: auto; } | |
| .section-head { | |
| align-items: start; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .grid { grid-template-columns: 1fr; } | |
| .card-top { min-height: auto; } | |
| .summary { min-height: 0; } | |
| .pc { grid-template-columns: 1fr; } | |
| .compare-bar { | |
| align-items: stretch; | |
| flex-wrap: wrap; | |
| } | |
| .compare-info { flex-basis: 100%; } | |
| .footer-grid { grid-template-columns: 1fr; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header class="topbar"> | |
| <div class="shell topbar-inner"> | |
| <div class="brand"> | |
| <img src="wearables.png" alt="Wearables logo" onerror="this.style.display='none'" /> | |
| <div> | |
| <div class="brand-title">Wearables Explorer</div> | |
| <div class="brand-sub">Independent curated comparison</div> | |
| </div> | |
| </div> | |
| <div class="status-pill" title="Curated snapshot"> | |
| <span class="status-dot"></span> | |
| Updated 14 Sep 2026 | |
| </div> | |
| </div> | |
| </header> | |
| <main> | |
| <section class="shell hero"> | |
| <div> | |
| <div class="eyebrow">⌁ Selected wearables, clearly explained</div> | |
| <h1> | |
| Find the wearable that | |
| <span class="gradient">fits your life.</span> | |
| </h1> | |
| <p> | |
| Compare selected smartwatches, sports watches, smart rings and trackers | |
| by compatibility, strengths, trade-offs and intended use — without | |
| drowning in specifications. | |
| </p> | |
| </div> | |
| <aside class="hero-note"> | |
| <strong>A curated snapshot, not a paid ranking.</strong> | |
| <p> | |
| No sponsored placement. Every device links to an official source. | |
| Features can vary by country, phone, software version and regulatory approval. | |
| </p> | |
| <div class="stats"> | |
| <div class="stat"><b id="statDevices">8</b><span>devices</span></div> | |
| <div class="stat"><b>5</b><span>brands</span></div> | |
| <div class="stat"><b>3</b><span>compare at once</span></div> | |
| </div> | |
| </aside> | |
| </section> | |
| <section class="shell"> | |
| <div class="controls-wrap"> | |
| <div class="controls"> | |
| <input | |
| id="searchInput" | |
| class="input" | |
| type="search" | |
| placeholder="Search Apple, Garmin, ring, outdoor..." | |
| aria-label="Search wearables" | |
| /> | |
| <select id="typeFilter" class="select" aria-label="Filter by device type"> | |
| <option value="all">All device types</option> | |
| <option value="Smartwatch">Smartwatch</option> | |
| <option value="Sports watch">Sports watch</option> | |
| <option value="Smart ring">Smart ring</option> | |
| <option value="Smart band">Smart band</option> | |
| </select> | |
| <select id="sortFilter" class="select" aria-label="Sort devices"> | |
| <option value="newest">Newest first</option> | |
| <option value="name">Name A–Z</option> | |
| <option value="brand">Brand A–Z</option> | |
| </select> | |
| </div> | |
| <div class="quick-filters" aria-label="Compatibility filters"> | |
| <button class="chip active" data-compat="all">All phones</button> | |
| <button class="chip" data-compat="iPhone">iPhone</button> | |
| <button class="chip" data-compat="Android">Android</button> | |
| <button class="chip" data-use="outdoor">Outdoor</button> | |
| <button class="chip" data-use="sleep">Sleep</button> | |
| <button class="chip" data-use="fitness">Fitness</button> | |
| </div> | |
| </div> | |
| <div class="section-head"> | |
| <div> | |
| <h2>Selected recent wearables</h2> | |
| <p>Short explanations first. Specifications second.</p> | |
| </div> | |
| <div id="resultCount">8 devices</div> | |
| </div> | |
| <div id="deviceGrid" class="grid"></div> | |
| </section> | |
| </main> | |
| <footer class="footer"> | |
| <div class="shell footer-grid"> | |
| <div> | |
| <strong>Independent information project</strong> | |
| <p> | |
| Wearables Explorer is not affiliated with or endorsed by the manufacturers | |
| listed here. Manufacturer claims are summarized from official product, | |
| newsroom or support sources. | |
| </p> | |
| <p class="tiny"> | |
| Health and wellness features are informational and are not a substitute | |
| for professional medical advice, diagnosis or treatment. | |
| </p> | |
| </div> | |
| <div> | |
| <strong>About this version</strong> | |
| <p> | |
| Static Hugging Face Space. No account, tracking profile or API key is | |
| required for the comparison interface. | |
| </p> | |
| <p class="tiny">Explore the signals. Understand the limits. Choose more clearly.</p> | |
| </div> | |
| </div> | |
| </footer> | |
| <div id="compareBar" class="compare-bar" aria-live="polite"> | |
| <div class="compare-info"> | |
| <b id="compareCount">0 selected</b> | |
| <span id="compareNames">Choose up to three devices</span> | |
| </div> | |
| <button id="clearCompare" class="btn">Clear</button> | |
| <button id="openCompare" class="btn primary">Compare now</button> | |
| </div> | |
| <div id="compareOverlay" class="overlay" role="dialog" aria-modal="true" aria-labelledby="compareTitle"> | |
| <div class="modal"> | |
| <div class="modal-head"> | |
| <h3 id="compareTitle">Wearable comparison</h3> | |
| <button id="closeCompare" class="icon-btn" aria-label="Close comparison">✕</button> | |
| </div> | |
| <div id="compareTable" class="table-wrap"></div> | |
| </div> | |
| </div> | |
| <script> | |
| const devices = [ | |
| { | |
| id: "apple-watch-series-12", | |
| brand: "Apple", | |
| name: "Apple Watch Series 12", | |
| type: "Smartwatch", | |
| released: "2026-09-09", | |
| newLabel: "New · Sep 2026", | |
| compatibility: ["iPhone"], | |
| use: ["fitness", "sleep", "everyday"], | |
| ecosystem: "iPhone", | |
| battery: "Varies by use", | |
| bestFor: "Health + everyday use", | |
| summary: "Apple’s newest mainstream watch adds a new Health Sensing System, higher-frequency heart-rate and HRV sensing, and a readiness score.", | |
| features: "S11 chip; Health Sensing System; readiness; ECG; sleep and fitness tracking", | |
| pros: [ | |
| "Deep iPhone integration", | |
| "Broad health, fitness and safety feature set" | |
| ], | |
| cons: [ | |
| "Requires iPhone", | |
| "Some features vary by region and eligibility" | |
| ], | |
| source: "https://www.apple.com/newsroom/2026/09/introducing-apple-watch-series-12-with-the-all-new-health-sensing-system/", | |
| glow: "rgba(110,168,255,.18)" | |
| }, | |
| { | |
| id: "apple-watch-ultra-4", | |
| brand: "Apple", | |
| name: "Apple Watch Ultra 4", | |
| type: "Sports watch", | |
| released: "2026-09-09", | |
| newLabel: "New · Sep 2026", | |
| compatibility: ["iPhone"], | |
| use: ["fitness", "sleep", "outdoor"], | |
| ecosystem: "iPhone", | |
| battery: "Up to 45h outdoor workout tracking", | |
| bestFor: "Sport + adventure", | |
| summary: "A rugged Apple Watch built for athletes and outdoor use, with the new Health Sensing System, readiness insights, satellite communication and longer endurance.", | |
| features: "S11; readiness; satellite communication; advanced GPS; health and workout tracking", | |
| pros: [ | |
| "Strong outdoor and safety feature set", | |
| "Longer endurance than the standard Apple Watch" | |
| ], | |
| cons: [ | |
| "Requires iPhone", | |
| "Large, premium sports-watch format" | |
| ], | |
| source: "https://www.apple.com/newsroom/2026/09/apple-unveils-apple-watch-ultra-4/", | |
| glow: "rgba(255,181,84,.16)" | |
| }, | |
| { | |
| id: "galaxy-watch9", | |
| brand: "Samsung", | |
| name: "Galaxy Watch9", | |
| type: "Smartwatch", | |
| released: "2026-07-22", | |
| newLabel: "2026", | |
| compatibility: ["Android"], | |
| use: ["fitness", "sleep", "everyday"], | |
| ecosystem: "Android · best with Galaxy", | |
| battery: "Up to ~40h, usage dependent", | |
| bestFor: "Android everyday use", | |
| summary: "Samsung’s current mainstream Galaxy Watch focuses on a comfortable fit, improved battery capacity, faster performance and practical Samsung Health insights.", | |
| features: "Wear OS; Samsung Health; Gemini; sleep, activity and wellness tracking", | |
| pros: [ | |
| "Strong Android smartwatch experience", | |
| "Useful health and ecosystem integration" | |
| ], | |
| cons: [ | |
| "Not compatible with iPhone", | |
| "Some features work best with Samsung Galaxy phones" | |
| ], | |
| source: "https://news.samsung.com/us/samsung-whats-new-galaxy-watch9/", | |
| glow: "rgba(91,137,255,.18)" | |
| }, | |
| { | |
| id: "galaxy-watch-ultra2", | |
| brand: "Samsung", | |
| name: "Galaxy Watch Ultra2", | |
| type: "Sports watch", | |
| released: "2026-07-22", | |
| newLabel: "2026", | |
| compatibility: ["Android"], | |
| use: ["fitness", "sleep", "outdoor"], | |
| ecosystem: "Android · best with Galaxy", | |
| battery: "Usage dependent", | |
| bestFor: "Android sport + outdoor", | |
| summary: "Samsung’s rugged flagship wearable is aimed at runners, training and outdoor use while retaining the connected features of the Galaxy Watch ecosystem.", | |
| features: "Titanium design; advanced fitness; Samsung Health; connected smartwatch features", | |
| pros: [ | |
| "Rugged premium build", | |
| "Strong match for Galaxy users who train outdoors" | |
| ], | |
| cons: [ | |
| "Not compatible with iPhone", | |
| "Bulky compared with mainstream smartwatches" | |
| ], | |
| source: "https://www.samsung.com/us/watches/", | |
| glow: "rgba(80,205,214,.15)" | |
| }, | |
| { | |
| id: "pixel-watch-5", | |
| brand: "Google", | |
| name: "Pixel Watch 5", | |
| type: "Smartwatch", | |
| released: "2026-08-01", | |
| newLabel: "New · 2026", | |
| compatibility: ["Android"], | |
| use: ["fitness", "sleep", "everyday"], | |
| ecosystem: "Android · optimized for Pixel", | |
| battery: "Up to 40h", | |
| bestFor: "Google + health ecosystem", | |
| summary: "Google’s newest Pixel Watch combines Google Health tracking with Gemini-powered coaching and expanded wellness sensing in a compact smartwatch format.", | |
| features: "Gemini; Google Health; ECG; advanced wellness sensors; up to 40h battery", | |
| pros: [ | |
| "Tight Google and Android integration", | |
| "Strong health and coaching focus" | |
| ], | |
| cons: [ | |
| "Not compatible with iPhone", | |
| "Some health capabilities depend on region or rollout" | |
| ], | |
| source: "https://store.google.com/product/pixel_watch_5?hl=en-US", | |
| glow: "rgba(129,216,174,.16)" | |
| }, | |
| { | |
| id: "garmin-fenix-9-pro", | |
| brand: "Garmin", | |
| name: "fēnix 9 Pro", | |
| type: "Sports watch", | |
| released: "2026-08-25", | |
| newLabel: "New · Aug 2026", | |
| compatibility: ["iPhone", "Android"], | |
| use: ["fitness", "sleep", "outdoor"], | |
| ecosystem: "iPhone + Android", | |
| battery: "Multi-day · varies by mode", | |
| bestFor: "Training + expeditions", | |
| summary: "Garmin’s flagship performance watch targets athletes and adventurers with extensive multisport tools, advanced navigation and connected outdoor capabilities.", | |
| features: "Multisport GPS; stamina metrics; navigation; satellite + LTE on Pro models", | |
| pros: [ | |
| "Excellent outdoor and endurance focus", | |
| "Works with both iPhone and Android" | |
| ], | |
| cons: [ | |
| "Complex feature set for casual users", | |
| "Premium performance-watch positioning" | |
| ], | |
| source: "https://www.garmin.com/en-US/newsroom/press-release/outdoor/garmin-expands-its-flagship-performance-smartwatch-lineup-with-fenix9-and-fenix9-pro/", | |
| glow: "rgba(64,221,176,.16)" | |
| }, | |
| { | |
| id: "garmin-cirqa", | |
| brand: "Garmin", | |
| name: "CIRQA Smart Band", | |
| type: "Smart band", | |
| released: "2026-07-21", | |
| newLabel: "New · Jul 2026", | |
| compatibility: ["iPhone", "Android"], | |
| use: ["fitness", "sleep"], | |
| ecosystem: "iPhone + Android", | |
| battery: "Up to 10 days", | |
| bestFor: "Screen-free health tracking", | |
| summary: "Garmin’s first screen-free smart band is designed for distraction-free 24/7 wellness and activity tracking with data viewed in Garmin Connect.", | |
| features: "No display; 24/7 health tracking; activity detection; Garmin Connect; no subscription required", | |
| pros: [ | |
| "Screen-free and low distraction", | |
| "Up to 10 days of battery life" | |
| ], | |
| cons: [ | |
| "No on-device display", | |
| "Less suitable for people wanting rich smartwatch apps" | |
| ], | |
| source: "https://www.garmin.com/en-US/newsroom/press-release/wearables-health/meet-cirqa-smart-band-the-screen-free-health-and-fitness-tracker-from-garmin/", | |
| glow: "rgba(69,231,194,.16)" | |
| }, | |
| { | |
| id: "oura-ring-5", | |
| brand: "Oura", | |
| name: "Oura Ring 5", | |
| type: "Smart ring", | |
| released: "2026-05-28", | |
| newLabel: "2026", | |
| compatibility: ["iPhone", "Android"], | |
| use: ["sleep", "fitness"], | |
| ecosystem: "iPhone + Android", | |
| battery: "Typically 6–9 days", | |
| bestFor: "Sleep + recovery", | |
| summary: "Oura’s newest generation is a slimmer titanium smart ring focused on continuous health signals, sleep, recovery and long-term wellness insights.", | |
| features: "Titanium; temperature sensing; heart-rate sensing; sleep and recovery insights", | |
| pros: [ | |
| "Compact, screen-free form factor", | |
| "Strong sleep and recovery focus" | |
| ], | |
| cons: [ | |
| "Active membership is needed for the full software experience", | |
| "No smartwatch-style screen or apps" | |
| ], | |
| source: "https://support.ouraring.com/hc/en-us/articles/50997181300243-Discover-Oura-Ring-5", | |
| glow: "rgba(190,150,255,.17)" | |
| } | |
| ]; | |
| let activeCompat = "all"; | |
| let activeUse = null; | |
| let selected = new Set(); | |
| const grid = document.getElementById("deviceGrid"); | |
| const searchInput = document.getElementById("searchInput"); | |
| const typeFilter = document.getElementById("typeFilter"); | |
| const sortFilter = document.getElementById("sortFilter"); | |
| const resultCount = document.getElementById("resultCount"); | |
| const compareBar = document.getElementById("compareBar"); | |
| const compareCount = document.getElementById("compareCount"); | |
| const compareNames = document.getElementById("compareNames"); | |
| const compareOverlay = document.getElementById("compareOverlay"); | |
| const compareTable = document.getElementById("compareTable"); | |
| document.getElementById("statDevices").textContent = devices.length; | |
| function safeText(str) { | |
| return String(str) | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">") | |
| .replace(/"/g, """); | |
| } | |
| function getFiltered() { | |
| const query = searchInput.value.trim().toLowerCase(); | |
| const type = typeFilter.value; | |
| let list = devices.filter(d => { | |
| const text = [ | |
| d.brand, d.name, d.type, d.summary, d.features, | |
| d.ecosystem, d.bestFor, ...d.use | |
| ].join(" ").toLowerCase(); | |
| const matchesQuery = !query || text.includes(query); | |
| const matchesType = type === "all" || d.type === type; | |
| const matchesCompat = activeCompat === "all" || d.compatibility.includes(activeCompat); | |
| const matchesUse = !activeUse || d.use.includes(activeUse); | |
| return matchesQuery && matchesType && matchesCompat && matchesUse; | |
| }); | |
| if (sortFilter.value === "newest") { | |
| list.sort((a,b) => b.released.localeCompare(a.released)); | |
| } else if (sortFilter.value === "name") { | |
| list.sort((a,b) => a.name.localeCompare(b.name)); | |
| } else if (sortFilter.value === "brand") { | |
| list.sort((a,b) => a.brand.localeCompare(b.brand) || a.name.localeCompare(b.name)); | |
| } | |
| return list; | |
| } | |
| function render() { | |
| const list = getFiltered(); | |
| resultCount.textContent = `${list.length} ${list.length === 1 ? "device" : "devices"}`; | |
| if (!list.length) { | |
| grid.innerHTML = `<div class="empty">No matching wearables. Try a broader search or reset a filter.</div>`; | |
| return; | |
| } | |
| grid.innerHTML = list.map(d => { | |
| const isSelected = selected.has(d.id); | |
| return ` | |
| <article class="card"> | |
| <div class="card-top" style="--glow:${d.glow}"> | |
| <div class="card-meta"> | |
| <span class="brand-tag">${safeText(d.brand)}</span> | |
| <span class="new-tag">${safeText(d.newLabel)}</span> | |
| </div> | |
| <h3 class="device-name">${safeText(d.name)}</h3> | |
| <p class="device-type">${safeText(d.type)} · ${safeText(d.ecosystem)}</p> | |
| </div> | |
| <div class="card-body"> | |
| <p class="summary">${safeText(d.summary)}</p> | |
| <div class="keyline"> | |
| <div class="key"> | |
| <span>Battery</span> | |
| <b>${safeText(d.battery)}</b> | |
| </div> | |
| <div class="key"> | |
| <span>Best for</span> | |
| <b>${safeText(d.bestFor)}</b> | |
| </div> | |
| </div> | |
| <div class="pc"> | |
| <div class="pros"> | |
| <div class="pc-title">Pros</div> | |
| <ul> | |
| ${d.pros.map(x => `<li>${safeText(x)}</li>`).join("")} | |
| </ul> | |
| </div> | |
| <div class="cons"> | |
| <div class="pc-title">Cons</div> | |
| <ul> | |
| ${d.cons.map(x => `<li>${safeText(x)}</li>`).join("")} | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="card-actions"> | |
| <a | |
| class="btn" | |
| href="${d.source}" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| aria-label="Open official source for ${safeText(d.name)}" | |
| > | |
| Official source ↗ | |
| </a> | |
| <button | |
| class="btn ${isSelected ? "selected" : "primary"}" | |
| data-compare="${d.id}" | |
| aria-pressed="${isSelected}" | |
| aria-label="${isSelected ? "Remove from" : "Add to"} comparison: ${safeText(d.name)}" | |
| > | |
| ${isSelected ? "✓ Added" : "+ Compare"} | |
| </button> | |
| </div> | |
| </div> | |
| </article> | |
| `; | |
| }).join(""); | |
| document.querySelectorAll("[data-compare]").forEach(btn => { | |
| btn.addEventListener("click", () => toggleCompare(btn.dataset.compare)); | |
| }); | |
| } | |
| function toggleCompare(id) { | |
| if (selected.has(id)) { | |
| selected.delete(id); | |
| } else { | |
| if (selected.size >= 3) { | |
| alert("You can compare up to three wearables at once."); | |
| return; | |
| } | |
| selected.add(id); | |
| } | |
| updateCompareBar(); | |
| render(); | |
| } | |
| function updateCompareBar() { | |
| const list = devices.filter(d => selected.has(d.id)); | |
| compareBar.classList.toggle("show", list.length > 0); | |
| compareCount.textContent = `${list.length} selected`; | |
| compareNames.textContent = list.length | |
| ? list.map(d => d.name).join(" · ") | |
| : "Choose up to three devices"; | |
| } | |
| function openComparison() { | |
| const list = devices.filter(d => selected.has(d.id)); | |
| if (list.length < 2) { | |
| alert("Select at least two wearables to compare."); | |
| return; | |
| } | |
| const rows = [ | |
| ["Type", d => d.type], | |
| ["Compatibility", d => d.compatibility.join(" + ")], | |
| ["Ecosystem", d => d.ecosystem], | |
| ["Battery", d => d.battery], | |
| ["Best for", d => d.bestFor], | |
| ["Key features", d => d.features], | |
| ["Pros", d => d.pros.join(" • ")], | |
| ["Cons", d => d.cons.join(" • ")] | |
| ]; | |
| compareTable.innerHTML = ` | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Compare</th> | |
| ${list.map(d => `<th>${safeText(d.name)}</th>`).join("")} | |
| </tr> | |
| </thead> | |
| <tbody> | |
| ${rows.map(([label, getter]) => ` | |
| <tr> | |
| <td>${safeText(label)}</td> | |
| ${list.map(d => `<td>${safeText(getter(d))}</td>`).join("")} | |
| </tr> | |
| `).join("")} | |
| <tr> | |
| <td>Official source</td> | |
| ${list.map(d => ` | |
| <td> | |
| <a href="${d.source}" target="_blank" rel="noopener noreferrer">Open source ↗</a> | |
| </td> | |
| `).join("")} | |
| </tr> | |
| </tbody> | |
| </table> | |
| `; | |
| compareOverlay.classList.add("open"); | |
| document.body.style.overflow = "hidden"; | |
| } | |
| function closeComparison() { | |
| compareOverlay.classList.remove("open"); | |
| document.body.style.overflow = ""; | |
| } | |
| searchInput.addEventListener("input", render); | |
| typeFilter.addEventListener("change", render); | |
| sortFilter.addEventListener("change", render); | |
| document.querySelectorAll(".chip").forEach(chip => { | |
| chip.addEventListener("click", () => { | |
| if (chip.dataset.compat) { | |
| activeCompat = chip.dataset.compat; | |
| activeUse = null; | |
| document.querySelectorAll(".chip").forEach(c => c.classList.remove("active")); | |
| chip.classList.add("active"); | |
| } else if (chip.dataset.use) { | |
| const clickedUse = chip.dataset.use; | |
| const wasActive = activeUse === clickedUse; | |
| activeUse = wasActive ? null : clickedUse; | |
| activeCompat = "all"; | |
| document.querySelectorAll(".chip").forEach(c => c.classList.remove("active")); | |
| const allPhones = document.querySelector('[data-compat="all"]'); | |
| if (activeUse) { | |
| chip.classList.add("active"); | |
| } else { | |
| allPhones.classList.add("active"); | |
| } | |
| } | |
| render(); | |
| }); | |
| }); | |
| document.getElementById("openCompare").addEventListener("click", openComparison); | |
| document.getElementById("clearCompare").addEventListener("click", () => { | |
| selected.clear(); | |
| updateCompareBar(); | |
| render(); | |
| }); | |
| document.getElementById("closeCompare").addEventListener("click", closeComparison); | |
| compareOverlay.addEventListener("click", e => { | |
| if (e.target === compareOverlay) closeComparison(); | |
| }); | |
| document.addEventListener("keydown", e => { | |
| if (e.key === "Escape" && compareOverlay.classList.contains("open")) { | |
| closeComparison(); | |
| } | |
| }); | |
| render(); | |
| updateCompareBar(); | |
| </script> | |
| </body> | |
| </html> | |