Spaces:
Running on Zero
Running on Zero
|
Download docs/SPIKE-VERDICT.md from WolfDavid/japanese-learning-avatar: direct link, hf CLI and curl.
- Browser
- Download file 6.89 kB
-
https://huggingface.co/spaces/WolfDavid/japanese-learning-avatar/resolve/03d5ccf002944b946c90c8a7b5e432a5a156aa6e/docs/SPIKE-VERDICT.md
- Command line
-
hf download hf://spaces/WolfDavid/japanese-learning-avatar@03d5ccf002944b946c90c8a7b5e432a5a156aa6e/docs/SPIKE-VERDICT.md
-
curl -L -o SPIKE-VERDICT.md https://huggingface.co/spaces/WolfDavid/japanese-learning-avatar/resolve/03d5ccf002944b946c90c8a7b5e432a5a156aa6e/docs/SPIKE-VERDICT.md
6.89 kB
| # Wave 0 spike verdict (AVTR-01) | |
| **Date:** 2026-09-05 **Space revision:** `487b8cf` (code; `82717b7` docs on top) **Transport:** inline | |
| The question this spike existed to answer: can three.js + `@pixiv/three-vrm` render a VRM with | |
| idle life inside a Gradio 6 `gr.HTML` component on a real, public, ZeroGPU Hugging Face Space, | |
| and survive the host's re-render paths β or does the avatar have to live in an iframe? | |
| `01-RESEARCH.md` Β§ "The honest gap" found no prior art either way: every three.js Space on the | |
| Hub is `sdk: static`, and none of Gradio's own `gr.HTML` examples load a third-party ES module. | |
| ## Automated evidence | |
| All values are read as numbers out of `window.Avatar.getDebug()` on the public URL by | |
| `tests/e2e/test_avatar_loop.py --space-url https://wolfdavid-japanese-learning-avatar.hf.space` | |
| (5 passed, run twice on 2026-09-05 against `487b8cf`). Never a screenshot diff. | |
| | Check | Value | Pass | | |
| |---|---|---| | |
| | threeInstanceCount (deployed) | 1 | β | | |
| | mountCount after 20 interactions | 1 (send Γ7, fill+send Γ7, checkbox Γ6; `ready` still true, threeInstanceCount still 1) | β | | |
| | vrmMetaTitle | `VRM1_Constraint_Twist_Sample` (vrmSpecVersion `1`) | β | | |
| | blink max over 12 s | 1.0 β 3 completed blinks (`blinkCount`), full-closure frame observed | β | | |
| | distinct breath values over 12 s | 169 (170 samples at animation-frame rate) | β | | |
| | console: "Multiple instances of Three.js" | absent | β | | |
| | console: "import map" | absent | β | | |
| | armDown left / right (rest pose, raw skeleton) | β0.932 / β0.932 (threshold < β0.7; 0 would be the T-pose) | β | | |
| | Space-page embed (`huggingface.co/spaces/β¦` cross-origin iframe) | `ready: true`, threeInstanceCount 1, mountCount 1, armDown β0.932, transport `inline` β read inside the iframe | β | | |
| | tutor.vrm served from the Space | 10,776,332 bytes transferred (`model/vrml`), not an LFS pointer | β | | |
| | Cold wake (Space already warm) | 0.2 s to first HTTP 200 β true sleepβwake is a 01-10 measurement | recorded | | |
| | Page load β `ready` | 4.09 s / 5.61 s / 5.66 s / 8.30 s across four loads; tutor.vrm 2.96β6.79 s of that | recorded | | |
| | Space runtime | `RUNNING`, hardware `zero-a10g`, `DISABLE_GPU=1`; rebuilt to RUNNING in 106 s after push | β | | |
| **Console noise on the deployed page, none of it a spike token:** one `404` from | |
| `https://huggingface.co/api/organizations/WolfDavid/avatar` (Gradio's own Hub-integration | |
| lookup, not a project resource); deprecation warnings for `VRMUtils.removeUnnecessaryJoints` | |
| (three-vrm says use `combineSkeletons`, which we already call) and `THREE.Clock` (use | |
| `THREE.Timer`); headless-GPU `ReadPixels` stall warnings that do not occur on a real GPU. The | |
| two deprecations are cheap to retire when plan 01-10 vendors the modules. | |
| ## Human observation | |
| **Desktop:** Chromium 151.0.7922.34 (Playwright, headless, 1100Γ900 and 1280Γ900) β | |
| `docs/evidence/2026-09-05-deployed-rest-pose.png` (direct URL) and | |
| `docs/evidence/2026-09-05-hub-embed.png` (the Space page on huggingface.co, "Running on ZERO" | |
| badge visible). Character renders upper-body, face readable, not clipped; hair, skin and | |
| T-shirt in correct MToon toon shading; arms hang in a relaxed A-pose; the pixiv credit line is | |
| visible under the controls. The earlier build `41ee90e` was confirmed **T-posed** by the project | |
| owner and by `docs/evidence/2026-09-05-deployed-tpose.png` β that was a missing rest pose | |
| (nothing ever moved the arms), *not* the two-instances symptom, and it is fixed in `7a26764`. | |
| The project owner gave the verdict on this evidence on 2026-09-05. | |
| **Mobile:** β **NOT YET TESTED ON A REAL DEVICE.** Plan 01-10 (2026-09-06) ran Playwright device | |
| emulation instead β the `Pixel 7` descriptor on Chromium renders and completes a turn on the direct | |
| URL and inside the Hub page; the `iPhone 14` descriptor could not be exercised (Playwright's Windows | |
| WebKit has no Web Audio) β recorded as EMULATED in `docs/LATENCY.md Β§ Mobile`. Fill in from a real | |
| phone: `<device> / <OS version> / <browser>` β renders y/n β smooth or slideshow. This row is a | |
| plan-01-05 acceptance criterion and an AVTR-01 manual-only verification; until it is | |
| recorded, **AVTR-01 stays Pending** even though every automated check passes. | |
| **Space-page embed (huggingface.co/spaces/WolfDavid/japanese-learning-avatar):** the app | |
| loads inside the Hub's cross-origin iframe (`?__theme=system`), the avatar reaches `ready`, | |
| and the same debug numbers read identically from inside the frame. No mixed-content, no | |
| third-party-cookie, no `allow=` issue surfaced for rendering. (Microphone permission inside | |
| this embed is a plan 01-08/01-09 question, not this spike's.) | |
| ## Verdict | |
| **CONFIRMED: `gr.HTML` hosts three.js/VRM on a deployed Gradio 6 Space.** This is a publicly | |
| novel result β no prior art existed. Keeping `AVATAR_TRANSPORT=inline`. | |
| The iframe transport (`avatar/avatar-iframe.js` + `avatar/stage.html`) stays in the tree as | |
| the tested fallback it was built to be; `tests/e2e/test_facade_parity.py` keeps proving both | |
| transports expose byte-identical method and debug surfaces, so flipping the env var remains a | |
| config change rather than a re-plan. | |
| ## Consequences for later plans | |
| - **None for the architecture.** The `window.Avatar` facade, `turn-loop.js` and the | |
| six-method `stagePort` seam are exactly as designed; 01-08 wires `dispatchTurn` / | |
| `requestSlower` against them with no transport awareness. | |
| - **AVTR-01 is not closed by this verdict.** Its last open item is the mobile row above. | |
| Record it, then mark the requirement. | |
| - **A green suite is not a correct picture.** The deployed avatar passed `test_vrm_ready`, | |
| `test_idle_life` and `test_no_remount` while standing in a T-pose. The fix added | |
| `armDown` and a `< β0.7` assertion at three layers (standalone stage, both transports, | |
| deployed). The standing rule for 01-08/01-09: **any visual property a human would notice must | |
| be published as a number and asserted**, before the phase is called done. | |
| - **`ready` fires before the first frame renders,** and the first frame compiles every MToon | |
| shader (>1.5 s measured headless). Post-render measurements must wait for | |
| `breathValue !== 0`, never a fixed sleep. 01-09's deployed lip-sync tests inherit this. | |
| - **`window.Avatar.__debug` is a stale snapshot** refreshed only by `getDebug()`. Always | |
| `await window.Avatar.getDebug()` per sample; `IDLE_SAMPLER` in `test_avatar_loop.py` is the | |
| reference pattern. | |
| - **01-10 latency harness inputs recorded here:** pageβready 4.1β8.3 s warm; tutor.vrm | |
| 3.0β6.8 s of that over the public internet; Space rebuild-to-RUNNING 106 s; warm wake 0.2 s. | |
| True cold-from-sleep wake (48 h `gcTimeout`) is still unmeasured. | |
| - **01-10 vendoring:** replace `THREE.Clock` with `THREE.Timer` and drop the deprecated | |
| `removeUnnecessaryJoints` call while pinning the vendored modules. | |