WolfDavid commited on
Commit
50d6810
·
1 Parent(s): 648b932

docs(01-10): record the mobile row as emulated, with the real-device row left open

Browse files

No phone was available, so the row is Playwright device emulation and says so:
the Pixel 7 descriptor on Chromium renders the avatar and completes a typed
turn on both the direct URL and inside the Hub page's iframe (one three.js
instance, arms posed, 7-8 fps under SwiftShader, speech-start 8.0-8.8 s after
Enter); the iPhone 14 descriptor cannot be exercised because Playwright's
Windows WebKit has no Web Audio API and the boot aborts before the stage
mounts. AVTR-01 is deliberately not marked on this evidence; the section ends
with what a real-device check must record to close it.

docs/LATENCY.md CHANGED
@@ -54,11 +54,21 @@ What this is and is not: a **pause/restart reuses the built image**, which is wh
54
 
55
  ## Mobile
56
 
57
- | Device | OS | Browser | Renders? | Observed smoothness | Push-to-talk | Turn latency |
58
- |---|---|---|---|---|---|---|
59
- | **PENDING - Task 3 (owner)** | | | | | | |
 
 
 
 
 
 
 
 
 
 
60
 
61
- Open the Space on a real phone via the huggingface.co Space page, not only the direct subdomain; record device, OS version, browser version, renders / smooth-or-slideshow, warmth, whether the mic permission and push-to-talk worked, and a rough turn time.
62
 
63
  ## Lip-sync verification (AVTR-02)
64
 
 
54
 
55
  ## Mobile
56
 
57
+ **EMULATED — real-device verification still open.** No real phone was available; these rows are Playwright device descriptors driven by the execution agent on the owner's instruction, and they say nothing about a real mobile GPU, thermals or the mobile microphone-permission flow. AVTR-01's manual row therefore stays **open** and the requirement is **not** marked on this evidence. Space revision `b4d182ba9d4ccf77c9910375c9842ddf29496a22`, 2026-09-06T12:32:52Z; raw record `docs/evidence/2026-09-06-mobile-emulation.json`; screenshots `docs/evidence/2026-09-06-mobile-emulated-*.png`.
58
+
59
+ | Device (EMULATED) | OS | Browser | URL | Renders? | Observed smoothness | Push-to-talk | Turn latency | Page -> ready / first frame |
60
+ |---|---|---|---|---|---|---|---|---|
61
+ | Playwright `Pixel 7` descriptor (412x839 CSS px, DPR 2.625, touch, mobile UA) | Android 14 UA string | Chromium 151.0.7922.34 headless, WebGL 2 via **SwiftShader** (no GPU) | direct `hf.space` | **yes** — `ready`, first frame, `threeInstanceCount` 1, `mountCount` 1, `armDown` -0.932 / -0.932, canvas 324x480 CSS (648x960 buffer) | **7.7 fps** over 5 s (rAF = getDebug samples) — a slideshow, but that is the software rasteriser on this laptop, not a phone GPU | **not tested** (mobile mic permission needs a device) | typed こんにちは -> speech-start **8.0 s** after Enter; `lastTurnMs` 6612, `synthesis_ms` 5694; mouth peaks aa/ih/oh 1.0; audio 1.056 s | 4.5 s / 6.0 s |
62
+ | same `Pixel 7` descriptor | Android 14 UA | same Chromium | **huggingface.co Space page** (inside the Hub's `iframe.space-iframe`, `?__theme=system`) | **yes** — same numbers read inside the iframe: 1 instance, mount 1, arms posed, "Running on ZERO" badge above the avatar | **7.3 fps** (SwiftShader) | not tested | speech-start **8.8 s** after Enter; `lastTurnMs` 7354, `synthesis_ms` 6012; turn completed | 5.7 s / 8.0 s |
63
+ | Playwright `iPhone 14` descriptor (390x664, DPR 3, touch, iOS UA) | iOS UA string | **WebKit 26.5, Playwright's Windows build** — WebGL 2 present ("Apple GPU"), **no Web Audio API** (`AudioContext` and `webkitAudioContext` both `undefined`) | direct and Hub page | **NO — not a device result.** Boot aborts before the stage mounts: `avatar boot failed: TypeError: undefined is not a constructor (evaluating 'new AudioCtor()')`, status "the avatar failed to load - see the browser console", blank canvas (`…iphone14-webkit-bootfail.png`) | — | — | — | — |
64
+
65
+ What the emulation does and does not establish:
66
+
67
+ - **Established on the Android/Chromium profile:** the responsive layout stacks the canvas above the controls at a phone width; the VRM, the idle life and a full typed turn (server round trip, decode, lip-synced playback) work at mobile viewport, DPR and user agent, both on the direct URL and embedded in the Hub page. The Hub page swaps its iframe once while resolving the Space (a frame found too early detaches), and the Hub's own script logs one `getBoundingClientRect` error at that moment — neither is the app's.
68
+ - **Not established:** frame rate on a phone (SwiftShader's 7–8 fps is this laptop's CPU rasterising a 648x960 buffer; a real Adreno/Mali/Apple GPU is a different measurement), warmth, battery, the mobile mic-permission and push-to-talk flow, and anything about Safari: **the iPhone rows are a host limitation, not an iOS result.** Real iOS Safari 14.5+ ships `AudioContext`, so the boot is expected to succeed there — but it is expected, not observed.
69
+ - **Finding for the product (deferred, `deferred-items.md`):** the boot constructs the `AudioContext` before the stage mounts (`avatar/avatar.js:58-59`), so a browser without Web Audio gets a blank canvas even though rendering needs no audio. Constructing it lazily on the first turn or mic press would let the avatar render everywhere and only degrade sound.
70
 
71
+ **To close the row:** open `https://huggingface.co/spaces/WolfDavid/japanese-learning-avatar` on a real phone; record device, OS version, browser version, renders / smooth-or-slideshow, warmth, whether the mic permission and push-to-talk worked, and a rough turn time; then mark AVTR-01.
72
 
73
  ## Lip-sync verification (AVTR-02)
74
 
docs/evidence/2026-09-06-mobile-emulated-iphone14-webkit-bootfail.png ADDED

Git LFS Details

  • SHA256: 3a0b4f40f60a0df3f87972361824b69d1a6f385a71267ef68e40e4ebdf8b869b
  • Pointer size: 130 Bytes
  • Size of remote file: 59.1 kB
docs/evidence/2026-09-06-mobile-emulated-pixel7-direct.png ADDED

Git LFS Details

  • SHA256: 91ecc86dad2f3f3d294748ecc5b40b0c47d8ba7e5593b9bf62448da0c6a422ed
  • Pointer size: 131 Bytes
  • Size of remote file: 322 kB
docs/evidence/2026-09-06-mobile-emulated-pixel7-hub.png ADDED

Git LFS Details

  • SHA256: f6f37614f75120a87906ddce05f75399ce823f8f9544ad6309707a31eca7fe69
  • Pointer size: 131 Bytes
  • Size of remote file: 309 kB
docs/evidence/2026-09-06-mobile-emulation.json ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "started_at": "2026-09-06T12:32:52.511194+00:00",
3
+ "runs": [
4
+ {
5
+ "device": "Pixel 7",
6
+ "engine": "chromium",
7
+ "url": "direct",
8
+ "descriptor": {
9
+ "viewport": {
10
+ "width": 412,
11
+ "height": 839
12
+ },
13
+ "device_scale_factor": 2.625,
14
+ "is_mobile": true,
15
+ "has_touch": true
16
+ },
17
+ "browser_version": "151.0.7922.34",
18
+ "frame_url": "https://wolfdavid-japanese-learning-avatar.hf.space/",
19
+ "ready_s": 4.5,
20
+ "first_frame_s": 6.0,
21
+ "renders": true,
22
+ "threeInstanceCount": 1,
23
+ "armDown": {
24
+ "left": -0.9320020565105094,
25
+ "right": -0.9320044170363805
26
+ },
27
+ "mountCount": 1,
28
+ "transport": "inline",
29
+ "vrmMetaTitle": "VRM1_Constraint_Twist_Sample",
30
+ "webgl": {
31
+ "version": "WebGL 2.0 (OpenGL ES 3.0 Chromium)",
32
+ "renderer": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)"
33
+ },
34
+ "viewport": {
35
+ "w": 412,
36
+ "h": 839,
37
+ "dpr": 2.625,
38
+ "ua": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36"
39
+ },
40
+ "canvas": {
41
+ "css": [
42
+ 324,
43
+ 480
44
+ ],
45
+ "buffer": [
46
+ 648,
47
+ 960
48
+ ]
49
+ },
50
+ "fps": {
51
+ "seconds": 5.08,
52
+ "rafPerSecond": 7.677165354330708,
53
+ "debugSamplesPerSecond": 7.677165354330708
54
+ },
55
+ "turn_speech_start_s": 8.0,
56
+ "turn": {
57
+ "completed": true,
58
+ "lastTurnMs": 6612,
59
+ "timings": {
60
+ "audio_query_ms": 1.28,
61
+ "synthesis_ms": 5693.787,
62
+ "timeline_ms": 0.223,
63
+ "encode_ms": 0.105,
64
+ "server_total_ms": 5695.751
65
+ },
66
+ "visemePeaks": {
67
+ "aa": 1,
68
+ "ih": 1,
69
+ "ou": 0,
70
+ "ee": 0,
71
+ "oh": 1
72
+ },
73
+ "turnCount": 1,
74
+ "lastError": null,
75
+ "audioContextState": [
76
+ 1.056
77
+ ]
78
+ },
79
+ "attempts": [],
80
+ "page_errors": [],
81
+ "console_errors": [
82
+ "error: Failed to load resource: the server responded with a status of 404 ()",
83
+ "warning: [.WebGL-0x26c001c0400]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels",
84
+ "warning: [.WebGL-0x26c001c0400]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels",
85
+ "warning: [.WebGL-0x26c001c0400]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels",
86
+ "warning: [.WebGL-0x26c001c0400]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels (this message will no longer repeat)"
87
+ ],
88
+ "status_text": "ready",
89
+ "audio_api": {
90
+ "AudioContext": "function",
91
+ "webkitAudioContext": "undefined"
92
+ }
93
+ },
94
+ {
95
+ "device": "Pixel 7",
96
+ "engine": "chromium",
97
+ "url": "hub",
98
+ "descriptor": {
99
+ "viewport": {
100
+ "width": 412,
101
+ "height": 839
102
+ },
103
+ "device_scale_factor": 2.625,
104
+ "is_mobile": true,
105
+ "has_touch": true
106
+ },
107
+ "browser_version": "151.0.7922.34",
108
+ "frame_url": "https://wolfdavid-japanese-learning-avatar.hf.space/?__theme=system",
109
+ "ready_s": 5.7,
110
+ "first_frame_s": 8.0,
111
+ "renders": true,
112
+ "threeInstanceCount": 1,
113
+ "armDown": {
114
+ "left": -0.9320199291170335,
115
+ "right": -0.9320222848803261
116
+ },
117
+ "mountCount": 1,
118
+ "transport": "inline",
119
+ "vrmMetaTitle": "VRM1_Constraint_Twist_Sample",
120
+ "webgl": {
121
+ "version": "WebGL 2.0 (OpenGL ES 3.0 Chromium)",
122
+ "renderer": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)"
123
+ },
124
+ "viewport": {
125
+ "w": 412,
126
+ "h": 2055,
127
+ "dpr": 1,
128
+ "ua": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36"
129
+ },
130
+ "canvas": {
131
+ "css": [
132
+ 324,
133
+ 480
134
+ ],
135
+ "buffer": [
136
+ 648,
137
+ 960
138
+ ]
139
+ },
140
+ "fps": {
141
+ "seconds": 5.096200000047684,
142
+ "rafPerSecond": 7.260311604657156,
143
+ "debugSamplesPerSecond": 7.260311604657156
144
+ },
145
+ "turn_speech_start_s": 8.8,
146
+ "turn": {
147
+ "completed": true,
148
+ "lastTurnMs": 7354,
149
+ "timings": {
150
+ "audio_query_ms": 0.996,
151
+ "synthesis_ms": 6011.549,
152
+ "timeline_ms": 0.181,
153
+ "encode_ms": 0.089,
154
+ "server_total_ms": 6013.038
155
+ },
156
+ "visemePeaks": {
157
+ "aa": 1,
158
+ "ih": 1,
159
+ "ou": 0,
160
+ "ee": 0,
161
+ "oh": 1
162
+ },
163
+ "turnCount": 1,
164
+ "lastError": null,
165
+ "audioContextState": [
166
+ 1.056
167
+ ]
168
+ },
169
+ "attempts": [
170
+ "Error: Frame.wait_for_selector: Frame was detached\nCall log:\n - waiting for locator(\"#vrm-stage\")\n"
171
+ ],
172
+ "page_errors": [
173
+ "Cannot read properties of undefined (reading 'getBoundingClientRect')"
174
+ ],
175
+ "console_errors": [
176
+ "warning: Unrecognized feature: 'ambient-light-sensor'.",
177
+ "warning: Unrecognized feature: 'battery'.",
178
+ "warning: Unrecognized feature: 'web-share'.",
179
+ "warning: Unrecognized feature: 'document-domain'.",
180
+ "warning: Unrecognized feature: 'layout-animations'.",
181
+ "warning: Unrecognized feature: 'legacy-image-formats'.",
182
+ "warning: Unrecognized feature: 'oversized-images'.",
183
+ "warning: Unrecognized feature: 'vr'."
184
+ ],
185
+ "status_text": "ready",
186
+ "audio_api": {
187
+ "AudioContext": "function",
188
+ "webkitAudioContext": "undefined"
189
+ }
190
+ },
191
+ {
192
+ "device": "iPhone 14",
193
+ "engine": "webkit",
194
+ "url": "direct",
195
+ "descriptor": {
196
+ "viewport": {
197
+ "width": 390,
198
+ "height": 664
199
+ },
200
+ "device_scale_factor": 3,
201
+ "is_mobile": true,
202
+ "has_touch": true
203
+ },
204
+ "browser_version": "26.5",
205
+ "frame_url": "https://wolfdavid-japanese-learning-avatar.hf.space/",
206
+ "error": "TimeoutError: Frame.wait_for_function: Timeout 60000ms exceeded.",
207
+ "attempts": [
208
+ "TimeoutError: Frame.wait_for_function: Timeout 60000ms exceeded."
209
+ ],
210
+ "page_errors": [],
211
+ "console_errors": [
212
+ "error: Failed to load resource: the server responded with a status of 404 ()",
213
+ "error: avatar boot failed: TypeError: undefined is not a constructor (evaluating 'new AudioCtor()')"
214
+ ],
215
+ "status_text": "the avatar failed to load - see the browser console",
216
+ "audio_api": {
217
+ "AudioContext": "undefined",
218
+ "webkitAudioContext": "undefined"
219
+ }
220
+ },
221
+ {
222
+ "device": "iPhone 14",
223
+ "engine": "webkit",
224
+ "url": "hub",
225
+ "descriptor": {
226
+ "viewport": {
227
+ "width": 390,
228
+ "height": 664
229
+ },
230
+ "device_scale_factor": 3,
231
+ "is_mobile": true,
232
+ "has_touch": true
233
+ },
234
+ "browser_version": "26.5",
235
+ "frame_url": "https://wolfdavid-japanese-learning-avatar.hf.space/?__theme=system",
236
+ "error": "TimeoutError: Frame.wait_for_function: Timeout 60000ms exceeded.",
237
+ "attempts": [
238
+ "Error: Frame.wait_for_selector: Frame was detached\nCall log:\n - waiting for locator(\"#vrm-stage\")\n",
239
+ "TimeoutError: Frame.wait_for_function: Timeout 60000ms exceeded."
240
+ ],
241
+ "page_errors": [],
242
+ "console_errors": [
243
+ "error: avatar boot failed: TypeError: undefined is not a constructor (evaluating 'new AudioCtor()')"
244
+ ],
245
+ "status_text": "the avatar failed to load - see the browser console",
246
+ "audio_api": {
247
+ "AudioContext": "undefined",
248
+ "webkitAudioContext": "undefined"
249
+ }
250
+ }
251
+ ]
252
+ }