| <!doctype html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>Digital Human on EDGE · Avatars</title> |
| |
| |
| |
| |
| <script src="/coi-serviceworker.js"></script> |
| |
| |
| |
| <script> |
| try { |
| if (localStorage.getItem("dh_booted_v1") === "1") |
| document.documentElement.classList.add("booted"); |
| } catch (e) {} |
| </script> |
| <style> |
| :root { |
| color-scheme: dark; |
| --bg: #0b0f17; |
| --panel: #111726; |
| --panel-2: #0e1320; |
| --card: #131a2a; |
| --border: #232c3d; |
| --border-soft: #1b2333; |
| --text: #e6edf3; |
| --muted: #8b97a8; |
| --muted-2: #5d6779; |
| --accent: #2f6bff; |
| --accent-soft: #1b2c52; |
| --good: #36d399; |
| --bad: #f85149; |
| --radius: 14px; |
| } |
| * { box-sizing: border-box; } |
| html, body { height: 100%; } |
| body { |
| margin: 0; |
| font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; |
| background: var(--bg); |
| color: var(--text); |
| } |
| button { font-family: inherit; } |
| |
| |
| .layout { display: flex; min-height: 100vh; } |
| |
| .topbar { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: 16px; |
| margin-bottom: 20px; |
| flex-wrap: wrap; |
| } |
| .brand { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| } |
| .brand-logo { |
| width: 30px; height: 30px; |
| border-radius: 9px; |
| background: linear-gradient(135deg, #7c5cff, #2f6bff); |
| display: grid; place-items: center; |
| font-weight: 800; font-size: 15px; color: #fff; |
| } |
| .brand-name { font-size: 15px; font-weight: 700; letter-spacing: 0.01em; } |
| |
| .contact-card { |
| display: flex; |
| align-items: baseline; |
| gap: 8px; |
| } |
| .contact-label { |
| font-size: 10px; font-weight: 700; letter-spacing: 0.06em; |
| text-transform: uppercase; color: var(--muted-2); |
| } |
| .contact-email { |
| font-size: 13px; font-weight: 600; color: var(--text); |
| text-decoration: none; |
| } |
| .contact-email:hover { color: var(--accent); } |
| |
| |
| .main { flex: 1; min-width: 0; padding: 26px 30px; } |
| .page-title { font-size: 26px; font-weight: 800; margin: 0 0 4px; } |
| .page-sub { color: var(--muted); font-size: 13px; margin: 0 0 16px; } |
| |
| .integration-banner { |
| display: flex; align-items: center; gap: 12px; |
| background: linear-gradient(90deg, var(--accent-soft), var(--panel)); |
| border: 1px solid #294270; |
| border-radius: 12px; |
| padding: 12px 16px; |
| margin-bottom: 22px; |
| } |
| .integration-banner > svg { |
| width: 20px; height: 20px; color: var(--accent); flex-shrink: 0; |
| } |
| .integration-text { font-size: 13px; color: var(--muted); line-height: 1.5; } |
| .integration-text strong { color: var(--text); font-weight: 700; margin-right: 4px; } |
| |
| .howto { |
| background: var(--panel); |
| border: 1px solid var(--border-soft); |
| border-radius: 12px; |
| padding: 14px 16px; |
| margin-bottom: 22px; |
| } |
| .howto-title { |
| font-size: 12px; font-weight: 700; letter-spacing: 0.04em; |
| text-transform: uppercase; color: var(--muted-2); margin: 0 0 10px; |
| } |
| .howto-steps { |
| display: grid; |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
| gap: 12px; |
| } |
| .howto-step { display: flex; align-items: flex-start; gap: 10px; } |
| .howto-num { |
| flex-shrink: 0; |
| width: 22px; height: 22px; border-radius: 50%; |
| background: var(--accent-soft); border: 1px solid #294270; |
| color: #fff; font-size: 12px; font-weight: 700; |
| display: grid; place-items: center; |
| } |
| .howto-step p { margin: 0; font-size: 13px; color: var(--muted); line-height: 1.45; } |
| .howto-step p strong { color: var(--text); font-weight: 600; } |
| .pill { |
| display: inline-block; |
| font-size: 11px; font-weight: 700; color: var(--text); |
| background: #1b2336; border: 1px solid var(--border-soft); |
| padding: 1px 7px; border-radius: 6px; |
| white-space: nowrap; |
| } |
| |
| .toolbar { |
| display: flex; align-items: center; gap: 12px; |
| margin-bottom: 22px; |
| } |
| .search { |
| position: relative; flex: 1; max-width: 360px; |
| } |
| .search svg { |
| position: absolute; left: 12px; top: 50%; transform: translateY(-50%); |
| width: 16px; height: 16px; color: var(--muted-2); |
| } |
| .search input { |
| width: 100%; |
| background: var(--panel); |
| border: 1px solid var(--border); |
| color: var(--text); |
| border-radius: 10px; |
| padding: 11px 12px 11px 36px; |
| font-size: 14px; |
| } |
| .search input::placeholder { color: var(--muted-2); } |
| .toolbar-spacer { flex: 1; } |
| .view-toggle { |
| display: flex; background: var(--panel); border: 1px solid var(--border); |
| border-radius: 10px; overflow: hidden; |
| } |
| .view-toggle button { |
| background: none; border: 0; color: var(--muted); |
| padding: 8px 10px; cursor: pointer; display: grid; place-items: center; |
| } |
| .view-toggle button.active { background: var(--accent); color: #fff; } |
| .view-toggle button svg { width: 18px; height: 18px; } |
| .btn-primary { |
| display: inline-flex; align-items: center; gap: 8px; |
| background: var(--accent); color: #fff; border: 0; |
| border-radius: 10px; padding: 11px 16px; |
| font-size: 14px; font-weight: 700; cursor: pointer; |
| } |
| .btn-primary svg { width: 16px; height: 16px; } |
| |
| |
| .gallery { |
| display: grid; |
| grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); |
| gap: 18px; |
| } |
| .gallery.list { grid-template-columns: 1fr; } |
| .gallery.list .card { flex-direction: row; align-items: center; } |
| .gallery.list .card-thumb { width: 120px; height: 80px; flex-shrink: 0; aspect-ratio: auto; } |
| .gallery.list .card-body { flex: 1; } |
| |
| .card { |
| background: var(--card); |
| border: 1px solid var(--border-soft); |
| border-radius: var(--radius); |
| overflow: hidden; |
| cursor: pointer; |
| display: flex; flex-direction: column; |
| transition: border-color 0.15s, transform 0.15s; |
| } |
| .card:hover { border-color: #2f3d57; transform: translateY(-2px); } |
| .card.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); } |
| .card-thumb { |
| position: relative; |
| width: 100%; aspect-ratio: 4 / 3; |
| background: #0a0e16; |
| overflow: hidden; |
| } |
| .card-thumb img { |
| width: 100%; height: 100%; object-fit: cover; object-position: center top; |
| display: block; |
| } |
| .card-thumb .thumb-skeleton { |
| position: absolute; inset: 0; |
| background: linear-gradient(100deg, #131a2a 30%, #1b2336 50%, #131a2a 70%); |
| background-size: 200% 100%; |
| animation: shimmer 1.2s linear infinite; |
| } |
| @keyframes shimmer { to { background-position: -200% 0; } } |
| .card-check { |
| position: absolute; top: 10px; right: 10px; |
| width: 22px; height: 22px; border-radius: 50%; |
| background: var(--accent); color: #fff; |
| display: none; place-items: center; |
| } |
| .card.selected .card-check { display: grid; } |
| .card-check svg { width: 13px; height: 13px; } |
| |
| .card-body { |
| padding: 12px 14px; |
| display: flex; align-items: center; justify-content: space-between; |
| gap: 8px; |
| } |
| .card-info { min-width: 0; } |
| .card-name { font-size: 15px; font-weight: 700; margin-bottom: 5px; } |
| .status { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); } |
| .status .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--good); } |
| .card-menu { |
| background: none; border: 0; color: var(--muted-2); cursor: pointer; |
| padding: 4px; border-radius: 6px; line-height: 0; |
| } |
| .card-menu:hover { color: var(--text); background: #1b2336; } |
| .card-menu svg { width: 18px; height: 18px; } |
| |
| .empty { |
| grid-column: 1 / -1; |
| text-align: center; color: var(--muted-2); |
| padding: 40px; font-size: 14px; |
| } |
| .gallery-loading { |
| grid-column: 1 / -1; |
| display: flex; flex-direction: column; align-items: center; gap: 14px; |
| padding: 48px 20px; color: var(--muted); |
| } |
| .gallery-loading .gl-text { font-size: 13px; font-weight: 600; } |
| .gallery-loading .gl-bar { |
| width: min(320px, 70%); height: 6px; |
| background: #131a2a; border: 1px solid var(--border-soft); |
| border-radius: 999px; overflow: hidden; position: relative; |
| } |
| .gallery-loading .gl-bar::after { |
| content: ""; position: absolute; top: 0; left: 0; height: 100%; |
| width: 40%; border-radius: 999px; background: var(--accent); |
| animation: gl-indeterminate 1.1s ease-in-out infinite; |
| } |
| @keyframes gl-indeterminate { |
| 0% { left: -40%; } |
| 100% { left: 100%; } |
| } |
| .gallery-foot { text-align: center; color: var(--muted-2); font-size: 12px; margin-top: 22px; } |
| |
| |
| .detail { |
| position: fixed; top: 0; right: 0; bottom: 0; |
| width: 380px; |
| background: var(--panel); |
| border-left: 1px solid var(--border); |
| overflow: hidden; |
| transform: translateX(100%); |
| transition: transform 0.25s ease; |
| z-index: 20; |
| display: flex; flex-direction: column; |
| } |
| .detail.open { transform: translateX(0); } |
| |
| |
| |
| .detail.landscape { width: min(760px, 64vw); } |
| .detail.landscape canvas#view { object-fit: contain; object-position: center; } |
| |
| |
| .detail-bar { |
| flex-shrink: 0; |
| padding: 16px; |
| border-bottom: 1px solid var(--border-soft); |
| background: var(--panel); |
| display: flex; flex-direction: column; gap: 12px; |
| } |
| .detail-bar-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; } |
| .detail-close { |
| width: 30px; height: 30px; border-radius: 8px; |
| background: #1b2336; border: 1px solid var(--border-soft); |
| color: var(--muted); cursor: pointer; display: grid; place-items: center; |
| flex-shrink: 0; |
| } |
| .detail-close:hover { color: var(--text); } |
| .detail-close svg { width: 15px; height: 15px; } |
| .detail-actions { display: flex; flex-wrap: nowrap; gap: 8px; } |
| .detail-actions > * { flex: 1 1 0; min-width: 0; } |
| |
| |
| .viewport { |
| position: relative; |
| flex: 1; min-height: 0; |
| width: 100%; |
| background: #000; overflow: hidden; |
| display: flex; align-items: center; justify-content: center; |
| } |
| canvas#view { |
| width: 100%; height: 100%; object-fit: cover; object-position: center top; |
| display: block; background: #000; |
| } |
| .fps-overlay { |
| position: absolute; top: 8px; right: 10px; |
| padding: 3px 8px; border-radius: 6px; |
| background: rgba(0, 0, 0, 0.55); color: #fff; |
| font-family: ui-monospace, SFMono-Regular, Menlo, monospace; |
| font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; |
| pointer-events: none; opacity: 0; transition: opacity 0.2s; |
| } |
| .fps-overlay.show { opacity: 1; } |
| .loading { |
| position: absolute; inset: 0; |
| display: flex; flex-direction: column; align-items: center; justify-content: center; |
| gap: 12px; padding: 20px; |
| background: rgba(11, 15, 23, 0.85); backdrop-filter: blur(2px); |
| text-align: center; transition: opacity 0.25s ease; z-index: 5; |
| } |
| .loading[hidden] { display: none; } |
| .loading.fade { opacity: 0; pointer-events: none; } |
| .spinner { |
| width: 34px; height: 34px; border-radius: 50%; |
| border: 3px solid rgba(255, 255, 255, 0.18); border-top-color: var(--accent); |
| animation: spin 0.8s linear infinite; |
| } |
| @keyframes spin { to { transform: rotate(360deg); } } |
| .loading-status { font-size: 13px; font-weight: 600; } |
| .loading-sub { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; min-height: 13px; } |
| .loading.err .spinner { animation: none; border-top-color: var(--bad); border-color: var(--bad); } |
| |
| |
| .boot-gate { |
| position: fixed; inset: 0; z-index: 1000; |
| display: flex; align-items: center; justify-content: center; |
| padding: 20px; |
| background: rgba(8, 11, 18, 0.72); |
| backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); |
| transition: opacity 0.35s ease; |
| } |
| .boot-gate.hide { opacity: 0; pointer-events: none; } |
| .boot-gate[hidden] { display: none; } |
| |
| html.booted .boot-gate { display: none; } |
| .boot-card { |
| width: min(420px, 92vw); |
| background: var(--panel); |
| border: 1px solid var(--border-soft); |
| border-radius: 16px; |
| padding: 30px 28px; |
| text-align: center; |
| box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55); |
| } |
| .boot-logo { |
| width: 46px; height: 46px; margin: 0 auto 16px; |
| border-radius: 12px; |
| background: linear-gradient(135deg, #7c5cff, #2f6bff); |
| display: grid; place-items: center; |
| font-weight: 800; font-size: 20px; color: #fff; |
| } |
| .boot-title { font-size: 18px; font-weight: 800; margin: 0 0 8px; } |
| .boot-desc { font-size: 12.5px; color: var(--muted); line-height: 1.5; margin: 0 0 18px; } |
| .boot-status { font-size: 13px; font-weight: 600; color: var(--text); margin: 0 0 10px; min-height: 16px; } |
| .boot-bar { |
| width: 100%; height: 8px; |
| background: #131a2a; border: 1px solid var(--border-soft); |
| border-radius: 999px; overflow: hidden; |
| } |
| .boot-bar-fill { |
| height: 100%; width: 0%; |
| background: linear-gradient(90deg, #7c5cff, #2f6bff); |
| border-radius: 999px; transition: width 0.25s ease; |
| } |
| .boot-pct { |
| font-size: 12px; color: var(--muted-2); margin: 10px 0 0; |
| font-variant-numeric: tabular-nums; min-height: 14px; |
| } |
| .boot-gate.err .boot-bar-fill { background: var(--bad); } |
| .boot-gate.err .boot-title { color: var(--bad); } |
| |
| .detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; } |
| .detail-name { font-size: 19px; font-weight: 800; margin: 0 0 6px; } |
| .btn-edit { |
| display: inline-flex; align-items: center; gap: 6px; |
| background: #1b2336; border: 1px solid var(--border-soft); color: var(--text); |
| border-radius: 9px; padding: 7px 12px; font-size: 13px; font-weight: 600; cursor: pointer; |
| } |
| .btn-edit svg { width: 14px; height: 14px; } |
| |
| .field { display: flex; flex-direction: column; gap: 8px; } |
| .field-label { |
| font-size: 11px; font-weight: 700; letter-spacing: 0.06em; |
| text-transform: uppercase; color: var(--muted-2); |
| } |
| .controls { display: flex; gap: 10px; } |
| .controls button { flex: 1 1 0; } |
| button.action { |
| background: var(--accent); color: #fff; border: 0; border-radius: 9px; |
| padding: 9px 10px; font-size: 13px; font-weight: 700; cursor: pointer; |
| display: inline-flex; align-items: center; justify-content: center; gap: 6px; |
| white-space: nowrap; overflow: hidden; text-overflow: ellipsis; |
| } |
| button.action.secondary { background: #1b2336; border: 1px solid var(--border-soft); } |
| button.action:disabled { opacity: 0.5; cursor: not-allowed; } |
| button.action svg { width: 15px; height: 15px; flex-shrink: 0; } |
| .filebtn { |
| background: #1b2336; border: 1px solid var(--border-soft); color: var(--text); |
| border-radius: 9px; padding: 9px 10px; font-size: 13px; font-weight: 700; |
| cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 6px; |
| white-space: nowrap; overflow: hidden; text-overflow: ellipsis; |
| } |
| .filebtn svg { width: 15px; height: 15px; flex-shrink: 0; } |
| .progress { |
| width: 100%; height: 6px; background: #0a0e16; |
| border: 1px solid var(--border-soft); border-radius: 4px; overflow: hidden; |
| } |
| .progress .bar { height: 100%; width: 0%; background: var(--accent); transition: width 0.1s linear; } |
| |
| .meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; padding-top: 6px; border-top: 1px solid var(--border-soft); } |
| .meta-label { font-size: 11px; color: var(--muted-2); margin-bottom: 4px; } |
| .meta-value { font-size: 13px; font-weight: 600; } |
| |
| @media (max-width: 900px) { |
| .detail { width: 100%; } |
| } |
| </style> |
| <script type="module" crossorigin src="/assets/index-CdVGhIO2.js"></script> |
| </head> |
| <body> |
| <div class="layout"> |
| |
| <main class="main"> |
| <header class="topbar"> |
| <div class="brand"> |
| <div class="brand-logo">DH</div> |
| <div class="brand-name">Digital Human on EDGE</div> |
| </div> |
| <div class="contact-card"> |
| <div class="contact-label">Contact</div> |
| <a class="contact-email" href="mailto:durgesh@infolabsglobal.ai">durgesh@infolabsglobal.ai</a> |
| </div> |
| </header> |
| <h1 class="page-title">Avatars</h1> |
| <p class="page-sub">Manage and preview your digital human avatars</p> |
|
|
| <div class="integration-banner"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z"/></svg> |
| <div class="integration-text"> |
| <strong>Runs on the edge.</strong> |
| Inference happens entirely in the browser — <span class="pill">no server deployment</span> |
| and <span class="pill">zero recurring cost</span>. Avatars plug into |
| <span class="pill">LiveKit</span> and <span class="pill">Pipecat</span> with support |
| for both <span class="pill">streaming</span> and <span class="pill">batch</span> inference. |
| </div> |
| </div> |
|
|
| <div class="howto"> |
| <h3 class="howto-title">How to use this demo</h3> |
| <div class="howto-steps"> |
| <div class="howto-step"> |
| <div class="howto-num">1</div> |
| <p><strong>Pick an avatar</strong> from the gallery below to open its live preview.</p> |
| </div> |
| <div class="howto-step"> |
| <div class="howto-num">2</div> |
| <p>Wait for the one-time setup to finish loading the avatar.</p> |
| </div> |
| <div class="howto-step"> |
| <div class="howto-num">3</div> |
| <p>Click <strong>Audio</strong> and choose any speech file to drive the lip-sync.</p> |
| </div> |
| <div class="howto-step"> |
| <div class="howto-num">4</div> |
| <p>Hit <strong>Play</strong> to watch it speak — or <strong>Download</strong> the result.</p> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="toolbar"> |
| <div class="search"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg> |
| <input id="avatarSearch" type="text" placeholder="Search avatars..." /> |
| </div> |
| <div class="toolbar-spacer"></div> |
| <div class="view-toggle" id="viewToggle"> |
| <button data-view="grid" class="active" title="Grid view"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg> |
| </button> |
| <button data-view="list" title="List view"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg> |
| </button> |
| </div> |
| </div> |
|
|
| <div id="gallery" class="gallery"></div> |
| <div id="galleryFoot" class="gallery-foot"></div> |
| </main> |
|
|
| |
| <aside id="detail" class="detail"> |
| <audio id="player" preload="auto" hidden></audio> |
|
|
| |
| <div class="detail-bar"> |
| <div class="detail-bar-top"> |
| <div> |
| <h2 class="detail-name" id="detailName">—</h2> |
| <div class="status"><span class="dot"></span> Active</div> |
| </div> |
| <button class="detail-close" id="detailClose" title="Close"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> |
| </button> |
| </div> |
| <div class="detail-actions"> |
| <label id="upload" class="filebtn"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg> |
| Audio |
| <input id="audioFile" type="file" accept="audio/*" hidden /> |
| </label> |
| <button id="play" class="action" disabled> |
| <svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><polygon points="6 4 20 12 6 20 6 4"/></svg> |
| Play |
| </button> |
| <button id="stop" class="action secondary" disabled> |
| <svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><rect x="6" y="6" width="12" height="12" rx="1"/></svg> |
| Stop |
| </button> |
| <button id="download" class="action secondary" disabled> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> |
| Download |
| </button> |
| </div> |
| <div id="progress" class="progress" hidden> |
| <div id="progressBar" class="bar"></div> |
| </div> |
| </div> |
|
|
| |
| <div class="viewport"> |
| <canvas id="view" width="512" height="384"></canvas> |
| <div id="fps" class="fps-overlay">—</div> |
| <div id="loading" class="loading"> |
| <div class="spinner"></div> |
| <div id="loadingStatus" class="loading-status">Loading…</div> |
| <div id="loadingSub" class="loading-sub"></div> |
| <div id="loadingProgress" class="progress" hidden> |
| <div id="loadingBar" class="bar"></div> |
| </div> |
| </div> |
| </div> |
| </aside> |
| </div> |
|
|
| |
| |
| <div id="bootGate" class="boot-gate"> |
| <div class="boot-card"> |
| <div class="boot-logo">DH</div> |
| <h2 class="boot-title">Preparing your digital human</h2> |
| <p class="boot-desc">Downloading avatar & model files — this runs once and is cached for next time.</p> |
| <p class="boot-status" id="bootStatus">Starting up…</p> |
| <div class="boot-bar"><div class="boot-bar-fill" id="bootBar"></div></div> |
| <p class="boot-pct" id="bootPct"></p> |
| </div> |
| </div> |
|
|
| </body> |
| </html> |
|
|