Dev voice feedback (R2) design
Dev voice feedback (R2) — design
Section titled “Dev voice feedback (R2) — design”Date: 2026-10-06. Status: approved by Chris (brainstorm, 2026-10-06).
In Dev builds only, pressing R2 (right trigger) on a controller opens the in-game feedback
panel with its text box focused and the system keyboard up, so a tester (Toby) can dictate
playtest feedback instead of typing it. Works on iPhone/iPad and Apple TV, and reuses the
existing feedback path (FeedbackPanel → GameplayTelemetry.send_feedback → EventQueue → D1).
Constraints (verified 2026-10-06)
Section titled “Constraints (verified 2026-10-06)”- A controller cannot invoke Siri. Dictation comes from the system keyboard: the mic key on iOS, and on tvOS the keyboard screen driven by the Siri Remote’s mic. Chris accepted that Toby picks up the Siri Remote for dictation on Apple TV.
- tvOS apps cannot record the microphone and
SFSpeechRecognizeris not on tvOS [Likely], so a custom speech path is not an option there. - The tvOS fork has no virtual keyboard today.
~/Claude/godot-tvos/godot/platform/tvos/ display_server_tvos.mmcarries aTODO: tvOS virtual keyboard support; the sharedvirtual_keyboard_showmessages akeyboardViewthat is never created on tvOS (nil, no-op).FeedbackPanel.text_entry_available()hides the text box on tvOS for this reason. FEATURE_VIRTUAL_KEYBOARDalready reports true on tvOS (shareddisplay_server_apple_embedded.mm), so it cannot distinguish an old template from a new one.- R2 (
JOY_AXIS_TRIGGER_RIGHT) is unbound. R1 = warp, L1 = decoy.
1. Game side (GDScript, both platforms)
Section titled “1. Game side (GDScript, both platforms)”- R2 binding —
input/input_router.gd: edge-triggered read ofJOY_AXIS_TRIGGER_RIGHT> 0.5 on any connected pad emits a newfeedback_requestedsignal. Gated onBuildConfig.dev_tools(). One emission per press (re-arms when the axis drops back below the threshold). - Routing —
main.gdconnects it to the existing_open_feedback_direct()(the touch speech-bubble path), so every “can we pause now” guard applies and the game resumes when the panel closes. It passes avoiceflag throughpause_menu.open_feedback_then_resume(voice). - Voice open — with
voice,FeedbackPanelopens on kind OTHER, focuses the text box, places the caret at the end and callsgrab_focus()so the system keyboard comes straight up. - Scope — R2 only acts where pause acts (in a run). No R2 in shop/title menus in v1.
Amended 2026-10-07 (Chris: “no matter what else is on the screen”, e.g. the death screen): R2
now opens main’s own top-layer overlay from ANY screen instead of routing through the pause menu;
input underneath is switched off while it is up (
InputFreeze) and a live run is frozen. Seedocs/architecture/dev-tools.md§ Dev R2. - Diagnostics off — same as the touch button: focus the Diagnostics toggle, no panel.
- tvOS gate —
text_entry_available()becomes: not tvOS, orOS.has_feature("tvos_text_input"). A build on an old template keeps the quick-notes-only panel instead of a dead text box. - Marker — the feedback body carries
voice: truefor R2-opened notes, sobh-feedback-triagecan tell them apart. (Check the Worker’s/eventsfeedback handling keeps unknown body keys; if it drops them, add the column/key there.) - No Debug Settings row — R2 is always on in Dev, so the console-parity rule does not apply.
Tests (GUT)
Section titled “Tests (GUT)”- R2 edge-detect fires once per press, re-arms on release.
- R2 does nothing when
dev_tools()is false. voiceopens the panel on OTHER with the text box focused.text_entry_available()follows thetvos_text_inputfeature on tvOS.voice: truereaches the feedback body.
2. Engine fork (~/Claude/godot-tvos/godot, branch tvos-render-1080p)
Section titled “2. Engine fork (~/Claude/godot-tvos/godot, branch tvos-render-1080p)”DisplayServerTVOSoverridesvirtual_keyboard_show/virtual_keyboard_hide/is_keyboard_active.- Show — present a
UIAlertControllerwith oneUITextFieldprefilled with the existing text, plus Done / Cancel, on the root view controller. Focusing the field brings up the full-screen tvOS keyboard (dictation via the Siri Remote mic). - Done — replace the Godot field’s contents via the same key-event injection iOS uses
(
DisplayServerAppleEmbedded::key): one BACKSPACE press/release per UTF-32 char of the existing text (caret is at the end, set by GDScript), then each character of the new text. - Cancel — send nothing; field unchanged.
- Feature —
OS_TVOS::_check_internal_feature_support("tvos_text_input")returns true. - Ship — commit on the local fork branch, rebuild + repackage the tvOS template
(
bh-appstore-release§0.55), verifystrings <binary> | grep tvos_text_inputbefore install. - Testing — no unit tests on the fork side; verified on-device (see Done).
3. Rollout, risks, done
Section titled “3. Rollout, risks, done”- Game side (§1) merged to main. Safe alone: iOS gets R2 + dictation immediately; tvOS keeps quick notes until the feature gate flips.
- Fork change + template repackage (§2).
- One Dev install on the Apple TV.
Release hygiene
Section titled “Release hygiene”- What’s new line in
control/src/whats_new.js(build: null), BUILD bump viabump-build.shafter checking live branches for higher BUILDs. - Store builds unaffected (R2 is
dev_tools()-gated); the fork change rides the next store tvOS template but is inert unless a text field opens.
- [Likely] With the alert up, the pad’s A/B may also leak into Godot. Fix if seen: swallow pad
input while
is_keyboard_active()is true. - [Guessing] The Siri Remote dictation affordance may need Dictation enabled in the Apple TV’s Settings. Device setting, not code.
Done when
Section titled “Done when”- iPhone: R2 → panel → keyboard → dictated note lands in D1 with
voice: true. - Apple TV: the same via the alert + Siri Remote mic.
scripts/gate.shgreen.