Spaces:
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/fbd985ff7754c8ea5773c2af17e7023a7b8e24fd/docs/SPIKE-VERDICT.md
- Command line
-
hf download hf://spaces/WolfDavid/japanese-learning-avatar@fbd985ff7754c8ea5773c2af17e7023a7b8e24fd/docs/SPIKE-VERDICT.md
-
curl -L -o SPIKE-VERDICT.md https://huggingface.co/spaces/WolfDavid/japanese-learning-avatar/resolve/fbd985ff7754c8ea5773c2af17e7023a7b8e24fd/docs/SPIKE-VERDICT.md
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.Avatarfacade,turn-loop.jsand the six-methodstagePortseam are exactly as designed; 01-08 wiresdispatchTurn/requestSloweragainst 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_lifeandtest_no_remountwhile standing in a T-pose. The fix addedarmDownand a< β0.7assertion 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. readyfires before the first frame renders, and the first frame compiles every MToon shader (>1.5 s measured headless). Post-render measurements must wait forbreathValue !== 0, never a fixed sleep. 01-09's deployed lip-sync tests inherit this.window.Avatar.__debugis a stale snapshot refreshed only bygetDebug(). Alwaysawait window.Avatar.getDebug()per sample;IDLE_SAMPLERintest_avatar_loop.pyis 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.ClockwithTHREE.Timerand drop the deprecatedremoveUnnecessaryJointscall while pinning the vendored modules.