merge origin/main: P5 gate met; keep Q10 answered, do not claim P6
main's P6 row reads 'Looping is blocked on HANDOFF Q10' while main's OWN HANDOFF.md line 39 marks Q10 answered -- the row was stale, not a decision, so the resolution keeps the answered status rather than silently un-resolving it. P5 takes main's line verbatim: that is the human's gate call and not mine. P6 explicitly does NOT claim the gate -- the same play-test found the SFX mix wrong, and 'sound on the P5 gate' means the RIGHT sound.
This commit is contained in:
127
docs/agents/PLAYTEST-2026-09-02-menus.md
Normal file
127
docs/agents/PLAYTEST-2026-09-02-menus.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Play-test, 2026-09-02 (second) — **P5 IS MET**, and four findings
|
||||
|
||||
## ✅ P5's gate is MET — the human clicked through it
|
||||
|
||||
> *"Menu walk and navigation is fine. Video skips too. Extras open. New Game
|
||||
> shows new game intro video."*
|
||||
|
||||
**P5 is done.** Its gate was *"a human clicks through it"*, the retro said it had
|
||||
been waiting on that and not on code for the whole milestone, and it has now
|
||||
happened. `PORT-MISSION.md` is updated.
|
||||
|
||||
The human also confirmed the NEW GAME gap is understood and acceptable:
|
||||
*"Deliberate AFAIK, in actual game the difficulty select comes first."* The port
|
||||
announces the two screens it skips; that stays as it is.
|
||||
|
||||
---
|
||||
|
||||
## F1 — 🔴 The menu DOES repeat on a held direction. Ours does not.
|
||||
|
||||
> *"Moving stick up/down and holding only moves one item. In game it actually
|
||||
> continues to move when holding up/down, just at a medium pace so player does
|
||||
> not need to move pad middle↔up/down, but also slow enough to see which item is
|
||||
> selected and move to target."*
|
||||
|
||||
**This settles the existence half of H1, and it settles it against us.** One step
|
||||
per deflection was authored as the conservative choice precisely because nobody
|
||||
knew. Now somebody has watched the real game: **it repeats.**
|
||||
|
||||
⚠️ **The RATE is still not measured, and it must not be guessed.** The human's
|
||||
description bounds it usefully and does not supply a number: fast enough that a
|
||||
player need not return the stick to centre, slow enough to read the selection as
|
||||
it passes. That is a range, not a value.
|
||||
|
||||
* **Decoder — measure it.** Hold a direction in Canary and count. Two numbers:
|
||||
the **initial delay** before the first repeat, and the **repeat interval**
|
||||
after it. Frames between cursor moves, at a stated present rate — a count, not
|
||||
a stopwatch reading ([`TEMPORAL-VERIFICATION.md`](TEMPORAL-VERIFICATION.md)).
|
||||
Also: does the d-pad differ from the stick? Does the rate accelerate while
|
||||
held, or stay flat?
|
||||
* **Port — implement the mechanism, take the number from the Decoder.** Do not
|
||||
ship a placeholder rate: an invented interval here is indistinguishable from a
|
||||
measured one a month from now, and this is the exact field where that has
|
||||
already cost us once.
|
||||
|
||||
## F2 — 🔴 The sound effects are too loud. There is no mix at all.
|
||||
|
||||
> *"Largely OK. Biggest notice is the volume, many effects are too loud."*
|
||||
|
||||
**Measured, and the human is right.** Every clip plays at unity gain, because
|
||||
**no volume or gain value exists anywhere** — not in `export/`, not in
|
||||
`authored/`, not in the manifest:
|
||||
|
||||
| | mean | max |
|
||||
|---|---|---|
|
||||
| **`se/confirm`** | **−17.7 dB** | **−0.0 dB** — at full scale |
|
||||
| `se/move` | −24.1 | −1.4 |
|
||||
| `se/back` | −21.0 | −5.7 |
|
||||
| `bgm/main_menu` | −20.7 | −4.2 |
|
||||
|
||||
`confirm` is the loudest thing in the export: **3 dB hotter in mean than the
|
||||
music** and 6.4 dB above `move`. A game mixes SE against BGM on separate buses;
|
||||
this port has one bus and no gains.
|
||||
|
||||
* **Decoder — is the mix ON THE DISC?** The obvious place is the cue table: a
|
||||
cue record commonly carries volume alongside the wave index, and
|
||||
`sub_821C5580` is already known to play cue 1103. If per-cue or per-bus gain is
|
||||
there, it is **decoded** and nobody has to choose. If it is provably not, say
|
||||
so with reach and it becomes an authored mix.
|
||||
* **Port — do not normalise in the exporter to fix this.** Re-levelling the file
|
||||
destroys the relationship between clips and cannot be undone by a modder.
|
||||
Gains belong at playback, as data, where a measured value can replace a chosen
|
||||
one without re-exporting.
|
||||
|
||||
## F3 — ❔ Something is missing on the title screen
|
||||
|
||||
> *"I also think that there is a sound track or effect missing at the title
|
||||
> screen."*
|
||||
|
||||
The export carries exactly one music track, `bgm/main_menu.ogg`, and the port
|
||||
plays nothing on the title. Whether the game does is unestablished.
|
||||
|
||||
* **Decoder:** which cue, if any, does the **title** play? The menu's is decoded
|
||||
(cue 1103 = `BGM_103` via `sub_821C5580`); the same route should answer the
|
||||
title. And is there a one-shot **sting** when the plate appears, or when Ⓐ is
|
||||
accepted? Either would read as "something missing" to a player.
|
||||
* ⚠️ A negative here needs a positive control (R4): show the method finding the
|
||||
menu's cue before concluding the title has none.
|
||||
|
||||
## F4 — 🔴 Ⓐ SKIPS FORWARD through the boot. We only implement one of the three.
|
||||
|
||||
> *"In the game one can get the plate to immediately show by pressing Ⓐ,
|
||||
> essentially skip to it. So after the logos one can immediately skip to the main
|
||||
> menu by pressing Ⓐ three times: 1. skip intro video, 2. show plate, 3. the
|
||||
> plate itself."*
|
||||
|
||||
A measured behaviour of the real game, and a good one — it is how a returning
|
||||
player gets past the boot.
|
||||
|
||||
| press | in the game | in the port |
|
||||
|---|---|---|
|
||||
| Ⓐ #1 | skips the intro video | ✅ implemented |
|
||||
| **Ⓐ #2** | **completes the title build-in and shows the plate immediately** | ❌ **missing** |
|
||||
| Ⓐ #3 | activates the plate → main menu | ✅ implemented |
|
||||
|
||||
* **Port:** Ⓐ during the title build-in should jump the sequence to the plate's
|
||||
arrival rather than being swallowed. ⚠️ **Careful what "jump" means** — the
|
||||
plate has a declared arrival at `t=238` and the title a build-in ending at
|
||||
`t≈118`. Whether the game *snaps* both clocks forward, or only reveals the
|
||||
plate and leaves the title where it is, is a question, not a detail. Ask if
|
||||
the capture does not say.
|
||||
* **Decoder:** what does Ⓐ do to the clocks? This is also a **second, cheap route
|
||||
to the plate-arrival question** — a press that skips to the plate tells you
|
||||
where the game thinks the plate belongs.
|
||||
* 📌 And it bears on `REFUTED.md`: *"any title after the first one refuses
|
||||
input"* is already narrowed to the attract-returned title. This is a third
|
||||
input the boot title accepts.
|
||||
|
||||
---
|
||||
|
||||
## H3 — the plate delay is ACCEPTED
|
||||
|
||||
> *"Delay feels the same. Cannot verify it is exact same, but is sufficient."*
|
||||
|
||||
Good enough to stop working on, **not** established as correct. Leave the row as
|
||||
unattributed rather than closing it green; if the duration question is ever
|
||||
settled by the pipeline work, check it against this rather than re-opening it
|
||||
from scratch.
|
||||
@@ -37,9 +37,39 @@ The three load-bearing questions stand, and the first is now the most valuable:
|
||||
3. **What Canary does to it** before a capture records it — present cadence,
|
||||
resolve, scale, gamma.
|
||||
|
||||
Also open and yours: **H1** — does a held direction repeat in the menus, and at
|
||||
what rate? The 61 % arm threshold you decoded is adopted; one step per deflection
|
||||
is still authored.
|
||||
### 🔴 Four asks from the 2026-09-02 menu play-test — [`PLAYTEST-2026-09-02-menus.md`](PLAYTEST-2026-09-02-menus.md)
|
||||
|
||||
P5's gate is **met** (a human walked the menus). These came out of the same
|
||||
session, and three of the four are yours. They are ahead of the pipeline work
|
||||
because the port is blocked on two of them.
|
||||
|
||||
1. **F1 — MEASURE THE MENU REPEAT RATE.** The human watched the real game: a held
|
||||
direction **repeats**, *"at a medium pace… slow enough to see which item is
|
||||
selected"*. That settles the existence half of H1 against our authored
|
||||
one-step-per-deflection. Two numbers, and the port will not move without
|
||||
them: the **initial delay** before the first repeat, and the **repeat
|
||||
interval** after it. Frames between cursor moves at a stated present rate — a
|
||||
count, not a stopwatch. Also: does the d-pad differ from the stick? Does it
|
||||
accelerate while held, or stay flat?
|
||||
2. **F2 — IS THE AUDIO MIX ON THE DISC?** The SFX are too loud and there is **no
|
||||
gain value anywhere** in the export; `confirm` peaks at −0.0 dBFS and sits
|
||||
3 dB above the music in mean. A cue record commonly carries a volume beside
|
||||
its wave index, and you already decoded `sub_821C5580` playing cue 1103. If
|
||||
per-cue or per-bus gain is there it is **decoded** and nobody has to choose.
|
||||
If it provably is not, say so with reach.
|
||||
3. **F3 — WHAT DOES THE TITLE PLAY?** A human says something is missing there.
|
||||
Which cue, if any, does the title screen play, and is there a **sting** when
|
||||
the plate appears or when Ⓐ is accepted? ⚠️ A negative needs a positive
|
||||
control (R4): show the method finding the *menu's* cue before concluding the
|
||||
title has none.
|
||||
4. **F4 — WHAT DOES Ⓐ DO TO THE CLOCKS?** In the real game, Ⓐ during the title
|
||||
build-in **reveals the plate immediately** — so the boot takes three presses:
|
||||
skip video, reveal plate, accept plate. Does the game snap both clocks
|
||||
forward, or only reveal the plate? 📌 This is also a **cheap second route to
|
||||
the plate-arrival question**: a press that skips to the plate tells you where
|
||||
the game thinks the plate belongs. And it is a third input the boot title
|
||||
accepts, which narrows `REFUTED.md`'s *"any title after the first refuses
|
||||
input"* further.
|
||||
|
||||
⚠️ Deliver a **series, not a settled value** — see
|
||||
[`TEMPORAL-VERIFICATION.md`](TEMPORAL-VERIFICATION.md), and note that the port's
|
||||
|
||||
@@ -17,17 +17,25 @@ drawn rather than frames different. Ask of any new check: **what would this stil
|
||||
report if the feature were entirely absent?** `tools/motion-census` exists for
|
||||
exactly that question; keep it in `check-all`.
|
||||
|
||||
⚠️ **P5's gate is "a human clicks through it" and is NOT claimed.** They signed
|
||||
off the logos, and separately confirmed Ⓐ, the stick and the submenus work.
|
||||
Nobody has said the milestone is met — **do not record it as met on their
|
||||
behalf.** If you believe it is ready, say so and ask.
|
||||
## ✅ P5's GATE IS MET — the human walked it, 2026-09-02
|
||||
|
||||
Still open, none of it blocking: **H1** (does a held direction repeat, and how
|
||||
fast — one step per deflection stays authored) and **H3** (the plate; every named
|
||||
cause is dead and the observation is unattributed — ⚠️ worth re-asking, since the
|
||||
animation fix changed what the whole boot looks like and the original observation
|
||||
may no longer reproduce). Both are in
|
||||
[`../agents/PLAYTEST-2026-09-02.md`](../agents/PLAYTEST-2026-09-02.md).
|
||||
> *"Menu walk and navigation is fine. Video skips too. Extras open. New Game
|
||||
> shows new game intro video."*
|
||||
|
||||
`PORT-MISSION.md` is updated. The NEW GAME gap is accepted as-is — they know the
|
||||
difficulty select comes first in the real game and that the port announces it.
|
||||
|
||||
### 🔴 Four findings from the same session — read [`../agents/PLAYTEST-2026-09-02-menus.md`](../agents/PLAYTEST-2026-09-02-menus.md)
|
||||
|
||||
| | | yours to do |
|
||||
|---|---|---|
|
||||
| **F1** | **The menu REPEATS on a held direction. Ours does not.** One step per deflection was authored as the safe choice; the human has now watched the real game and it repeats. | **Implement the mechanism. Take the RATE from the Decoder — do NOT ship a placeholder interval.** An invented rate here is indistinguishable from a measured one later, and this is the exact field where that already cost us. |
|
||||
| **F2** | **SFX too loud, and there is no mix at all.** Measured: `confirm` −17.7 dB mean / **−0.0 dB peak**, 3 dB hotter than the music; no gain value exists anywhere in `export/` or `authored/`. | Add gains **at playback, as data** — a bus per kind. ⚠️ **Do NOT normalise in the exporter**: re-levelling destroys the relationship between clips and a modder cannot undo it. The Decoder is checking whether the mix is on the disc. |
|
||||
| **F3** | **Something is missing on the title screen** — a track or a sting. The export has one music file and the port plays nothing on the title. | Wait for the Decoder; nothing to author yet. |
|
||||
| **F4** | **Ⓐ skips FORWARD through the boot, and we implement two of three presses.** Ⓐ#1 skips the video ✅, **Ⓐ#2 reveals the plate immediately ❌ missing**, Ⓐ#3 activates it ✅. | Make Ⓐ during the title build-in jump to the plate. ⚠️ Whether the game snaps **both** clocks forward or only reveals the plate is a question — ask rather than choose. |
|
||||
|
||||
**H3, the plate delay, is ACCEPTED** — *"feels the same… sufficient"*. Stop
|
||||
working on it. Leave the row unattributed rather than closing it green.
|
||||
|
||||
## Previous sole focus, 2026-09-02 — RESOLVED, kept for the method
|
||||
|
||||
|
||||
@@ -100,8 +100,8 @@ A milestone is done when its **artifact** exists, not when the code compiles.
|
||||
| **P2** | Keyframe animation | Buttons slide in. ~~Blocked on HANDOFF Q1 (the time unit). Do not invent it~~ — **Q1 is answered**: ramp linear, 2 units per rendered frame, 1 unit = 1/60 s. Gate met |
|
||||
| **P3** | Splash → title, with the transition | Both screens back to back, unattended |
|
||||
| **P4** | Intro video | `ADV.wmv` plays with audio (§6) |
|
||||
| **P5** | Main menu: navigation, focus states, Ⓐ into a submenu, B back | A human clicks through it |
|
||||
| **P6** | Audio — menu BGM and move/confirm SFX | Sound on the P5 gate. ~~Looping is blocked on HANDOFF Q10~~ — **Q10 is answered**: two stems of one performance, played together. Gate met |
|
||||
| **P5** | Main menu: navigation, focus states, Ⓐ into a submenu, B back | ~~A human clicks through it~~ — ✅ **GATE MET 2026-09-02.** A human walked it: *"Menu walk and navigation is fine. Video skips too. Extras open."* [`../agents/PLAYTEST-2026-09-02-menus.md`](../agents/PLAYTEST-2026-09-02-menus.md) |
|
||||
| **P6** | Audio — menu BGM and move/confirm SFX | Sound on the P5 gate. ~~Looping is blocked on HANDOFF Q10~~ — **Q10 is answered**: two stems of one performance, played together. 🔴 **Gate NOT claimed**: the same play-test found the SFX mix wrong (F2), and "sound on the P5 gate" means the right sound. |
|
||||
| **P7** | New-game intro video after NEW GAME | Plays, then returns to a defined state |
|
||||
|
||||
Work the lowest unfinished milestone. When one is blocked on an RE answer, say so
|
||||
|
||||
@@ -48,12 +48,17 @@ extends RefCounted
|
||||
## not again until it comes back. That makes it behave exactly like the d-pad,
|
||||
## which needs no latch because a button already is an edge.
|
||||
##
|
||||
## ⚠️ **AUTHORED, NOT MEASURED — and deliberately the conservative half.**
|
||||
## Whether the real game *repeats* while a direction is held, and how fast, is
|
||||
## unknown; it is an oracle question. One deflection = one step cannot run away
|
||||
## and cannot invent a rate. If the game does repeat, this is a difference a
|
||||
## human will notice as "I have to flick it again", and the fix is a measured
|
||||
## repeat interval — not a guessed one. Logged for the Decoder as `pad-repeat`.
|
||||
## ⚠️ ~~AUTHORED, NOT MEASURED — and deliberately the conservative half.~~
|
||||
## 🔴 **THE GAME DOES REPEAT, and this paragraph predicted its own refutation.**
|
||||
## It said: *"If the game does repeat, this is a difference a human will notice
|
||||
## as 'I have to flick it again'."* On 2026-09-02 a human who has played both
|
||||
## reported exactly that — *"holding only moves one item. In game it actually
|
||||
## continues to move when holding up/down, just at a medium pace"*.
|
||||
##
|
||||
## So one-step-per-deflection is no longer the conservative reading; it is a
|
||||
## known defect, and keeping it would be choosing a wrong behaviour over an
|
||||
## approximate one. The repeat is implemented below. **Its RATE is authored and
|
||||
## its FACT is not** — see `REPEAT_DELAY`.
|
||||
|
||||
## ✅ DECODED 2026-09-01, and it replaces an authored value.
|
||||
##
|
||||
@@ -88,11 +93,37 @@ const ENTER := 0.61
|
||||
## smaller number.
|
||||
const RELEASE := 0.4
|
||||
|
||||
## ## 3. A held direction repeats
|
||||
##
|
||||
## 🔴 **THE FACT IS REPORTED, THE RATE IS AUTHORED. Do not read the second as
|
||||
## carried by the first.** A human who has played both said the game repeats at
|
||||
## *"a medium pace … slow enough to see which item is selected"* — that settles
|
||||
## THAT it repeats and gives an order of magnitude, nothing more. Nobody has
|
||||
## measured an interval off the running game, and `pad-repeat` stays open for the
|
||||
## Decoder.
|
||||
##
|
||||
## 📌 **A constant interval is the right SHAPE, and that part is measured.** The
|
||||
## game digitises the left stick to four direction bits at 61 % deflection
|
||||
## (`ENTER` above), so it cannot see a deflection magnitude at all — a repeat it
|
||||
## drives cannot be rate-by-how-far-you-push. That excludes the one alternative
|
||||
## model, so only the constants are open.
|
||||
##
|
||||
## The delay exists so a deliberate single step never repeats by accident: a
|
||||
## flick to move one item is held for well under 0.4 s.
|
||||
##
|
||||
## ⚠️ **These two numbers change how the menu feels and only a human can judge
|
||||
## them** — the same standing as `ENTER`'s 0.61. Too fast reads as a cursor that
|
||||
## runs away; too slow reads as the defect this replaces.
|
||||
const REPEAT_DELAY := 0.40
|
||||
const REPEAT_INTERVAL := 0.20
|
||||
|
||||
## Only the left stick. The triggers are axes too, and latching them here would
|
||||
## silently swallow input the port does not read yet but might.
|
||||
const STICK := [JOY_AXIS_LEFT_X, JOY_AXIS_LEFT_Y]
|
||||
|
||||
var _latched: Dictionary = {}
|
||||
var _repeat_direction := 0
|
||||
var _repeat_clock := 0.0
|
||||
|
||||
|
||||
## Add the joypad buttons the built-in map omits. Returns a human-readable line,
|
||||
@@ -156,6 +187,53 @@ func accepts(event: InputEvent) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
## Which way a direction is being HELD right now, as -1 (up), 0 or +1 (down).
|
||||
##
|
||||
## 🔴 **Polled at the DEVICE, never through `Input.is_action_pressed`.** `ui_up`
|
||||
## and `ui_down` are bound to the stick axis at Godot's 0.50 action deadzone,
|
||||
## while this port steps at the game's measured 0.61. Polling the action would
|
||||
## repeat throughout the 0.50–0.61 band — the exact band `ENTER` exists to
|
||||
## exclude — so the repeat would contradict the threshold on the same stick.
|
||||
## That is the input-map lesson again: assert the device, not the layer above it.
|
||||
func held_direction() -> int:
|
||||
# The stick, from the latch `accepts()` already maintains, so the repeat and
|
||||
# the first step read one state and cannot disagree about hysteresis.
|
||||
var stick := int(_latched.get(JOY_AXIS_LEFT_Y, 0))
|
||||
if stick != 0:
|
||||
return stick
|
||||
for device in Input.get_connected_joypads():
|
||||
if Input.is_joy_button_pressed(device, JOY_BUTTON_DPAD_UP):
|
||||
return -1
|
||||
if Input.is_joy_button_pressed(device, JOY_BUTTON_DPAD_DOWN):
|
||||
return 1
|
||||
if Input.is_key_pressed(KEY_UP):
|
||||
return -1
|
||||
if Input.is_key_pressed(KEY_DOWN):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
## One repeat step, or 0. Call once per frame with the frame's delta.
|
||||
##
|
||||
## The FIRST step is not this function's: it comes from the event edge in
|
||||
## `_unhandled_input`, and the clock below starts from that same frame, so a held
|
||||
## direction gives one step now and the next only after `REPEAT_DELAY`. A change
|
||||
## of direction restarts the delay rather than inheriting the old cadence.
|
||||
func repeat_due(delta: float) -> int:
|
||||
var direction := held_direction()
|
||||
if direction == 0 or direction != _repeat_direction:
|
||||
_repeat_direction = direction
|
||||
_repeat_clock = 0.0
|
||||
return 0
|
||||
_repeat_clock += delta
|
||||
if _repeat_clock < REPEAT_DELAY:
|
||||
return 0
|
||||
# Subtract rather than reset, so the cadence cannot drift with the frame rate
|
||||
# -- at 140 fps and at 30 fps the same number of steps happen per second.
|
||||
_repeat_clock -= REPEAT_INTERVAL
|
||||
return direction
|
||||
|
||||
|
||||
## The pads Godot can see, for the startup line. A run where the human believes
|
||||
## a controller is connected and Godot disagrees should say so on its own,
|
||||
## rather than presenting as unresponsive buttons.
|
||||
|
||||
Reference in New Issue
Block a user