Ava visual upgrade: fitted face and skin, eyes, hair, teeth and lips, 3D turtleneck, glasses option, near-black background; retry dropped model downloads
Browse files- .gitattributes +1 -0
- avatars/ava-eye-spec.webp +0 -0
- avatars/ava-hd.glb +3 -0
- avatars/ava-lids.webp +0 -0
- chunk-3kpcdt7z.css +0 -1
- chunk-4t726cmy.css +1 -0
- chunk-afwf4ypr.js → chunk-ra2pzgep.js +0 -0
- index.html +5 -1
- workers/model-worker.js +5 -3
.gitattributes
CHANGED
|
@@ -34,3 +34,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
avatars/brunette.glb filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
avatars/brunette.glb filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
avatars/ava-hd.glb filter=lfs diff=lfs merge=lfs -text
|
avatars/ava-eye-spec.webp
ADDED
|
|
avatars/ava-hd.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:aba0e4fe8dce8d10a95a710041190facb0ce37bfef88d147fdc035986f222260
|
| 3 |
+
size 23848952
|
avatars/ava-lids.webp
ADDED
|
|
chunk-3kpcdt7z.css
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
:root{--bg:#0a0b10;--bg-elev:#13151c;--bg-elev-2:#1b1e29;--border:#ffffff14;--border-strong:#ffffff29;--text:#f5f6fa;--text-dim:#f5f6faa6;--text-faint:#f5f6fa6b;--error:#ff6a75;--live:#22d3ee;--font-mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace;--radius-sm:8px;--radius-md:14px}*{box-sizing:border-box}html,body{height:100%;margin:0}body{background:var(--bg);color:var(--text);overflow:hidden;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif}#app{position:relative;height:100dvh}#stage{position:absolute;inset:0}#stage canvas{display:block}[hidden]{display:none!important}#loading{position:absolute;display:grid;font-family:var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--text-faint);background:var(--bg);pointer-events:none;place-items: center;transition:opacity .6s;font-size:12px;font-weight:500;inset:0}#loading.done{opacity:0}#topbar{position:absolute;display:flex;pointer-events:none;justify-content:space-between;align-items: flex-start;padding:18px 20px;top:0;left:0;right:0}#topbar>*{pointer-events:auto}#identity h1{letter-spacing:.01em;margin:0;font-size:15px;font-weight:600}#identity p{color:var(--text-faint);max-width:340px;margin:4px 0 0;font-size:12px;line-height:1.45}#identity strong{color:var(--text-dim);font-weight:500}.icon-btn{display:grid;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev);color:var(--text-dim);cursor:pointer;touch-action:manipulation;place-items: center;width:36px;height:36px;padding:0;transition:color .15s,border-color .15s}.icon-btn:hover{color:var(--text);border-color:var(--border-strong)}.icon-btn.active{color:var(--error);border-color:var(--border-strong)}#main-btn{background:var(--text);color:var(--bg);cursor:pointer;touch-action:manipulation;border:none;border-radius:23px;min-width:190px;height:46px;padding:0 26px;transition:transform .12s,opacity .15s;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:14px;font-weight:600}#main-btn:hover:not(:disabled){transform:translateY(-1px)}#main-btn:disabled{pointer-events:none;opacity:.45;cursor:default}#main-btn.live{background:var(--bg-elev);color:var(--text);border:1px solid var(--border-strong)}#controls{position:absolute;display:flex;padding:0 20px calc(22px + env(safe-area-inset-bottom));flex-direction:column;align-items: center;gap:14px;bottom:0;left:0;right:0}#buttons{display:flex;align-items: center;gap:10px}#caption{font-family:var(--font-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--text-faint);transition:color .2s;font-size:11px;font-weight:500}#caption.live{color:var(--live)}#caption.error{color:var(--error);text-align:center;max-width:560px;line-height:1.5}#progress{background:var(--border-strong);overflow:hidden;border-radius:1px;width:min(240px,60vw);height:2px}#progress-fill{background:var(--text-dim);width:0;height:100%;transition:width .3s}#subtitles{position:absolute;border-radius:var(--radius-md);backdrop-filter:blur(6px);border:1px solid var(--border);text-align:center;text-wrap:balance;color:var(--text);opacity:0;pointer-events:none;display:-webkit-box;-webkit-line-clamp:3;overflow:hidden;background:#0a0b10b8;-webkit-box-orient:vertical;max-width:min(640px,100vw - 48px);padding:10px 16px;transition:opacity .25s;font-size:15px;line-height:1.5;bottom:118px;left:50%;transform:translate(-50%)}#subtitles.visible{opacity:1}#settings{border:1px solid var(--border-strong);border-radius:var(--radius-md);background:var(--bg-elev);color:var(--text);width:min(440px,100vw - 40px);padding:22px;box-shadow:0 4px 18px #00000052}#settings::backdrop{backdrop-filter:blur(2px);background:#05060999}#settings h2{margin:0 0 16px;font-size:15px;font-weight:600}#settings label{display:block;color:var(--text-dim);margin-bottom:14px;font-size:12px}#settings select,#settings textarea,#settings input{display:block;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev-2);color:var(--text);width:100%;margin-top:6px;padding:9px 11px;font-family:inherit;font-size:13px}#settings select:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings input:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea{resize:vertical}#settings .hint{display:block;margin-top:6px;font-size:11px;line-height:1.4}#settings .check-row{display:flex;align-items: center;gap:9px}#settings .check-row input{display:inline-block;accent-color:var(--text);width:auto;margin:0}.dialog-actions{display:flex;justify-content:space-between;gap:12px;margin-top:6px}#reset-prompt{color:var(--text-dim);cursor:pointer;background:0 0;border:none;padding:9px 0;font-size:13px}#reset-prompt:hover{color:var(--text)}.dialog-actions .primary{border-radius:var(--radius-sm);background:var(--text);color:var(--bg);cursor:pointer;border:none;padding:9px 20px;font-size:13px;font-weight:600}button:focus-visible{outline:2px solid var(--text-dim);outline-offset:2px}@media (prefers-reduced-motion:reduce){*{transition-duration:.01ms!important}}@media (max-width:600px){#identity p{display:none}#subtitles{font-size:14px;bottom:128px}}
|
|
|
|
|
|
chunk-4t726cmy.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
:root{--bg:#050506;--bg-elev:#13151c;--bg-elev-2:#1b1e29;--border:#ffffff14;--border-strong:#ffffff29;--text:#f5f6fa;--text-dim:#f5f6faa6;--text-faint:#f5f6fa6b;--error:#ff6a75;--live:#22d3ee;--font-mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace;--radius-sm:8px;--radius-md:14px}*{box-sizing:border-box}html,body{height:100%;margin:0}body{background:var(--bg);color:var(--text);overflow:hidden;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif}#app{position:relative;height:100dvh}#stage{position:absolute;background:#050506;inset:0}#stage canvas{display:block}[hidden]{display:none!important}#loading{position:absolute;display:grid;font-family:var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--text-faint);background:var(--bg);pointer-events:none;place-items: center;transition:opacity .6s;font-size:12px;font-weight:500;inset:0}#loading.done{opacity:0}#topbar{position:absolute;display:flex;pointer-events:none;justify-content:space-between;align-items: flex-start;padding:18px 20px;top:0;left:0;right:0}#topbar>*{pointer-events:auto}#identity h1{letter-spacing:.01em;margin:0;font-size:15px;font-weight:600}#identity p{color:var(--text-faint);max-width:340px;margin:4px 0 0;font-size:12px;line-height:1.45}#identity strong{color:var(--text-dim);font-weight:500}.icon-btn{display:grid;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev);color:var(--text-dim);cursor:pointer;touch-action:manipulation;place-items: center;width:36px;height:36px;padding:0;transition:color .15s,border-color .15s}.icon-btn:hover{color:var(--text);border-color:var(--border-strong)}.icon-btn.active{color:var(--error);border-color:var(--border-strong)}#main-btn{background:var(--text);color:var(--bg);cursor:pointer;touch-action:manipulation;border:none;border-radius:23px;min-width:190px;height:46px;padding:0 26px;transition:transform .12s,opacity .15s;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:14px;font-weight:600}#main-btn:hover:not(:disabled){transform:translateY(-1px)}#main-btn:disabled{pointer-events:none;opacity:.45;cursor:default}#main-btn.live{background:var(--bg-elev);color:var(--text);border:1px solid var(--border-strong)}#controls{position:absolute;display:flex;padding:0 20px calc(22px + env(safe-area-inset-bottom));flex-direction:column;align-items: center;gap:14px;bottom:0;left:0;right:0}#buttons{display:flex;align-items: center;gap:10px}#caption{font-family:var(--font-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--text-faint);transition:color .2s;font-size:11px;font-weight:500}#caption.live{color:var(--live)}#caption.error{color:var(--error);text-align:center;max-width:560px;line-height:1.5}#progress{background:var(--border-strong);overflow:hidden;border-radius:1px;width:min(240px,60vw);height:2px}#progress-fill{background:var(--text-dim);width:0;height:100%;transition:width .3s}#subtitles{position:absolute;border-radius:var(--radius-md);backdrop-filter:blur(6px);border:1px solid var(--border);text-align:center;text-wrap:balance;color:var(--text);opacity:0;pointer-events:none;display:-webkit-box;-webkit-line-clamp:3;overflow:hidden;background:#0a0b10b8;-webkit-box-orient:vertical;max-width:min(640px,100vw - 48px);padding:10px 16px;transition:opacity .25s;font-size:15px;line-height:1.5;bottom:118px;left:50%;transform:translate(-50%)}#subtitles.visible{opacity:1}#settings{border:1px solid var(--border-strong);border-radius:var(--radius-md);background:var(--bg-elev);color:var(--text);width:min(440px,100vw - 40px);padding:22px;box-shadow:0 4px 18px #00000052}#settings::backdrop{backdrop-filter:blur(2px);background:#05060999}#settings h2{margin:0 0 16px;font-size:15px;font-weight:600}#settings label{display:block;color:var(--text-dim);margin-bottom:14px;font-size:12px}#settings select,#settings textarea,#settings input{display:block;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg-elev-2);color:var(--text);width:100%;margin-top:6px;padding:9px 11px;font-family:inherit;font-size:13px}#settings select:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings input:focus-visible{outline:1px solid var(--text-dim);outline-offset:1px}#settings textarea{resize:vertical}#settings .hint{display:block;margin-top:6px;font-size:11px;line-height:1.4}#settings .check-row{display:flex;align-items: center;gap:9px}#settings .check-row input{display:inline-block;accent-color:var(--text);width:auto;margin:0}.dialog-actions{display:flex;justify-content:space-between;gap:12px;margin-top:6px}#reset-prompt{color:var(--text-dim);cursor:pointer;background:0 0;border:none;padding:9px 0;font-size:13px}#reset-prompt:hover{color:var(--text)}.dialog-actions .primary{border-radius:var(--radius-sm);background:var(--text);color:var(--bg);cursor:pointer;border:none;padding:9px 20px;font-size:13px;font-weight:600}button:focus-visible{outline:2px solid var(--text-dim);outline-offset:2px}@media (prefers-reduced-motion:reduce){*{transition-duration:.01ms!important}}@media (max-width:600px){#identity p{display:none}#subtitles{font-size:14px;bottom:128px}}
|
chunk-afwf4ypr.js → chunk-ra2pzgep.js
RENAMED
|
The diff for this file is too large to render.
See raw diff
|
|
|
index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
| 12 |
rel="stylesheet"
|
| 13 |
/>
|
| 14 |
|
| 15 |
-
<link rel="stylesheet" crossorigin href="./chunk-
|
| 16 |
<body>
|
| 17 |
<main id="app">
|
| 18 |
<!-- The avatar is the hero: a full-viewport 3D stage. -->
|
|
@@ -63,6 +63,10 @@
|
|
| 63 |
<input type="checkbox" id="subtitles-toggle" />
|
| 64 |
Show subtitles while she speaks
|
| 65 |
</label>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
<label>
|
| 67 |
System prompt
|
| 68 |
<textarea id="system-prompt" rows="10" spellcheck="false"></textarea>
|
|
|
|
| 12 |
rel="stylesheet"
|
| 13 |
/>
|
| 14 |
|
| 15 |
+
<link rel="stylesheet" crossorigin href="./chunk-4t726cmy.css"><script type="module" crossorigin src="./chunk-ra2pzgep.js"></script></head>
|
| 16 |
<body>
|
| 17 |
<main id="app">
|
| 18 |
<!-- The avatar is the hero: a full-viewport 3D stage. -->
|
|
|
|
| 63 |
<input type="checkbox" id="subtitles-toggle" />
|
| 64 |
Show subtitles while she speaks
|
| 65 |
</label>
|
| 66 |
+
<label class="check-row">
|
| 67 |
+
<input type="checkbox" id="glasses-toggle" />
|
| 68 |
+
Wear glasses
|
| 69 |
+
</label>
|
| 70 |
<label>
|
| 71 |
System prompt
|
| 72 |
<textarea id="system-prompt" rows="10" spellcheck="false"></textarea>
|
workers/model-worker.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
| 24 |
DeviceLostError,
|
| 25 |
} from "../vendor/Lfm3OmniForConditionalGeneration.js";
|
| 26 |
|
| 27 |
-
const LOAD_ATTEMPTS =
|
| 28 |
const LOAD_RETRY_MS = 1500;
|
| 29 |
// Her replies stay in history as text only: her speech costs ~16 tokens/s and left
|
| 30 |
// no room for what was said, so a 44-turn chat now fits and she still recalls it.
|
|
@@ -112,8 +112,10 @@ async function load({ model: modelId, system: sys }) {
|
|
| 112 |
console.warn(`model load attempt ${attempt} failed:`, err);
|
| 113 |
const adapterGlitch = /No WebGPU adapter/i.test(String(err?.message));
|
| 114 |
if (adapterGlitch && attempt === LOAD_ATTEMPTS) lastErr = Object.assign(new Error(err.message), { name: "WebGPUUnavailable" });
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
| 117 |
}
|
| 118 |
}
|
| 119 |
post({ kind: "failed", name: lastErr?.name ?? "Error", message: lastErr?.message ?? String(lastErr) });
|
|
|
|
| 24 |
DeviceLostError,
|
| 25 |
} from "../vendor/Lfm3OmniForConditionalGeneration.js";
|
| 26 |
|
| 27 |
+
const LOAD_ATTEMPTS = 4; // Chromium occasionally returns no adapter on a cold GPU process, and networks drop requests
|
| 28 |
const LOAD_RETRY_MS = 1500;
|
| 29 |
// Her replies stay in history as text only: her speech costs ~16 tokens/s and left
|
| 30 |
// no room for what was said, so a 44-turn chat now fits and she still recalls it.
|
|
|
|
| 112 |
console.warn(`model load attempt ${attempt} failed:`, err);
|
| 113 |
const adapterGlitch = /No WebGPU adapter/i.test(String(err?.message));
|
| 114 |
if (adapterGlitch && attempt === LOAD_ATTEMPTS) lastErr = Object.assign(new Error(err.message), { name: "WebGPUUnavailable" });
|
| 115 |
+
// A multi-gigabyte download over a real connection will sometimes drop a request. That's worth another go, after a growing pause; what's already cached isn't fetched again.
|
| 116 |
+
const networkGlitch = /failed to fetch|networkerror|network error|load failed|err_/i.test(String(err?.message));
|
| 117 |
+
if ((!adapterGlitch && !networkGlitch) || attempt === LOAD_ATTEMPTS) break;
|
| 118 |
+
await new Promise((r) => setTimeout(r, LOAD_RETRY_MS * 2 ** (attempt - 1)));
|
| 119 |
}
|
| 120 |
}
|
| 121 |
post({ kind: "failed", name: lastErr?.name ?? "Error", message: lastErr?.message ?? String(lastErr) });
|