feat(voice): render the pointer reticle beside the voice control

PointerReticle keeps the turn's timers and tool tracking and presents
where the user pointed to the gev-pointer-reticle store, one entry per
reticle; the command dock teleports each to the body with the same
class, aria-hidden, hidden state, target and position. The voice QA
reads the card and reticle after Vue's flush, and the application guide
says leaving out the command dock leaves out the voice control and its
reticle.
This commit is contained in:
Sameh Khamis committed 2026-10-31 20:36:39 -07:00
1 parent f9bf782b9c
commit 0926cbc105
11 files changed
+215 -78

No files matched your search

+2
View File
@@ -744,6 +744,8 @@
"server/providers/openai/toolDescriptions.js",
"src/voice/session.js",
"src/voice/sessionCommands.js",
"src/ui/stores/pointerReticle.js",
"src/voice/pointerReticleView.test.mjs",
"src/voice/realtimeSession.js",
"src/voice/realtimeEvents.js",
"src/voice/session.test.mjs",
+8 -4
View File
@@ -101,7 +101,8 @@
"src/ui/stores/sceneInteractions.js",
"src/ui/views/panels/SceneInteractions.vue",
"src/ui/stores/dataPacks.js",
"src/ui/views/panels/DataPacks.vue"
"src/ui/views/panels/DataPacks.vue",
"src/ui/stores/pointerReticle.js"
],
"external": ["vue", "pinia"]
},
@@ -2065,7 +2066,8 @@
"src/sources/requestDeadline.js",
"src/i18n/marker.js",
"src/ui/stores/voice.js",
"src/ui/vueRuntime.js"
"src/ui/vueRuntime.js",
"src/ui/stores/pointerReticle.js"
],
"external": ["vue", "pinia"]
},
@@ -3012,7 +3014,8 @@
"src/ui/stores/status.js",
"src/ui/toast.js",
"src/ui/stores/sceneInteractions.js",
"src/ui/stores/dataPacks.js"
"src/ui/stores/dataPacks.js",
"src/ui/stores/pointerReticle.js"
],
"external": [
"hls.js",
@@ -3979,7 +3982,8 @@
"src/ui/statusText.js",
"src/voice/providerCapabilities.js",
"src/ui/vueRuntime.js",
"src/ui/stores/voice.js"
"src/ui/stores/voice.js",
"src/ui/stores/pointerReticle.js"
],
"external": ["vue", "pinia"]
},
+3 -1
View File
@@ -1023,7 +1023,7 @@ async function runDeixisBehavior(page, run, settle) {
};
const beginAt = (x, y, said = null) =>
page.evaluate(
(px, py, text) => {
async (px, py, text) => {
const voice = window.__gevVoiceCommands;
if (text) {
// What the session emits for a spoken turn: a new turn, then the caption.
@@ -1043,6 +1043,8 @@ async function runDeixisBehavior(page, run, settle) {
voice.pointer.hold('keydown');
const snapshot = voice.beginPointerTurn('keydown');
voice.pointer.releaseHold();
// The voice card and the reticle render on Vue's next flush.
await Promise.resolve();
const chip = document.getElementById('gev-voice-card-pointer');
const reticle = document.querySelector('.gev-pointer-reticle');
return {