checkpoint: F10 GE-style refresh + distance defaults retune, D360-D370 series (local WIP; D370 pending user acceptance) — pre-wave baseline for the v0.4.0 modern-options wave

This commit is contained in:
James Dansereau committed 2026-09-27 16:18:20 -04:00
1 parent d8971fded0
commit c2c6fbdd68
10 files changed
+1048 -278

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
# F10 visual refresh — GoldenEye dossier styling (proposal)
Status: **superseded by D363 after user playtest** — the dossier/paper
concept below was implemented as D362, then replaced with a dark
watch-green/Bank Gothic version. This is the historical proposal for a
port-layer F10 overlay proposal, not a replacement for GE's pause watch or the
front-end PC Options screen. Reference surfaces: `src/game/front.c`
`constructor_menu15_cheat`/`frontSetupMenuBackground`, the existing
`port/src/frontoptions.c` cheat-list-inspired options screen, and GE's in-stage
watch. Current overlay: `port/src/optionsoverlay.c` `optionsOverlayEmit`,
`overlayRowAtY`, `sliderBarSpan`, `maxVisibleRows`.
## 1. Direction and boundaries
Make F10 read as an **MI6 dossier laid over the game scene**, not a generic
SDL debug panel: dark translucent scrim, warm paper/ivory content card,
black Zurich-style menu text, red for active options/slider fills and an
occasional muted gold title/accent. The front-end PC Options already uses
GE's actual 3D folder and Zurich text; use it as the visual reference, not
as a display-list dependency. In-stage F10 must remain an inexpensive flat
2D overlay: no loading a 3D wallet model, new ROM assets, front-end init
functions or `src/game` modifications. Preserve the current two-level
category -> settings navigation and the shared settings/commit API.
The initial port-only implementation lives in `optionsOverlayEmit()` and
uses one shared `OvLayout` for both 320x240 stage and 440x330 front canvases.
Headless captures live under `scratch/d362-test/` (not distributed). Manual
visual review on a bright stage and controller/mouse feel-check remain owed.
## 2. Concrete visual hierarchy
- **Backdrop/card:** keep an adjustable translucent dim over the scene;
replace the opaque blue-black rectangle with a near-opaque ivory panel
(subtle border and one offset shadow). Do not mimic the actual folder
texture unless a later, measured prototype proves the simple card
insufficient. Preserve legible contrast against both dark and bright
levels, including safe-area crop and widescreen pillarboxes.
- **Masthead:** small gold/black `MI6 / OPTIONS` or `PC OPTIONS` heading,
fine black rule (a restrained `CLASSIFIED` stamp can be added later if
measured text fits) rather than a blue title/instruction block. Keep the
category name on the **same
page above its first setting**, especially INPUT over Mouse sensitivity.
- **Root:** numbered `1. Input` ... `5. Video`, GE's dossier/menu numbering
and title case as on `frontoptions.c`; a narrow translucent dark selection
box behind the focused item. Category order and labels stay unchanged in
the shared row table; casing is presentation-only.
- **Section:** a compact `PREVIOUS`/Back tab, title and optional
`(Profile N)` annotation, then two columns: label at left, value at right.
Unselected values in black, active/toggled values in GE's dark red
(`0xA00000FF` is the cheat-screen reference). Slider tracks are thin
charcoal with a red fill and an obvious knob; show the numerical value
outside the bar. A mixed-scope `(per profile)` marker must remain legible
without colliding with the value column; measure it and, if necessary,
use a small second line rather than silently removing the distinction.
- **Actions:** Reset retains its two-press/three-second confirmation and
displays `CONFIRM` in red only while armed. Quit remains visually distinct
from resets (and retains its existing activation semantics). Back/Close
affordances should match the actual click targets, not become decoration.
- **Footer:** one quiet, short line for mouse/arrows/controller, with an
explicit `ESC: Back / F10: Close` cue. No newly invented glyphs or fonts
that may be missing from the game's text bank. FPS readout is independent.
Suggested layout sketch (not pixel positions):
```
MI6 / PC OPTIONS CLOSE
-----------------------------------------------
PREVIOUS GRAPHICS
Anti-aliasing 2x
Texture filter Bilinear
Draw distance [------|----] 50/100
...
Reset to defaults [ENTER]
ESC Back / F10 Close
```
## 3. Implementation boundaries
1. Extract a port-only layout helper for fonts, palette,
panel rectangles and spacing; preserve `rows[]`, `rowAdjust`, persistence,
file scoping, reset logic and input bindings. Use GE's loaded Zurich Bold
font for body *only after* validating it exists on both stage and front
contexts; Bank Gothic can remain a fallback/header font. Text clipping
must use the whole viewport as `textRender` expects.
2. Replace only the fill/text passes in `optionsOverlayEmit()` first. Emit
fills before text as currently, reset GBI state explicitly and keep
`OV_BUF_CMDS`/DL size bounds. Avoid mutable texture uploads or new assets.
3. One shared geometry calculation must drive panel/card positions,
`maxVisibleRows`, row Y, slider-bar span, close/back hitboxes, and
`overlayRowAtY`. In particular, don't change visual row spacing without
updating hit-testing (D304/D316), and don't use naive OS-window pixel
mapping instead of `gfx_get_ui_screen_rect` (D316/D335). When a page
scrolls, keep its section title visible; a clipped row cannot be clicked.
4. Use measured text widths to reserve space for values, `Confirm`,
`(Profile N)` and restart markers. At 320x240, allow scrolling/short
contextual hints, not overlapping text or tiny glyphs. At 440x330 and
ultrawide, centre or constrain the card rather than stretching the
columns across the entire viewport.
5. Make any GE-like UI sound effects opt-in to a *separate* follow-up: F10
runs in controller polling, and D361 prohibits game save/audio calls
from that thread. A cosmetic refresh must not reintroduce that lockup.
## 4. Acceptance gates
- Compare screenshots with the existing front Options/cheat dossier and the
in-stage watch; user reviews the live palette/layout before closing the task.
- Native 320x240, front-end 440x330, windowed 4:3, 16:9 and 21:9,
fullscreen, safe-area crop on/off: INPUT title visible; no text clipping,
unreadable values, wrong hitboxes, phantom/duplicated bottom rows or
overflow in the display list. Check graphics's longest labels and AUDIO's
per-profile markers with and without a valid file.
- Mouse click/drag/wheel, arrows and D-pad/stick, ESC back, F10/Start/X
close, focused/armed reset, and quit action all behave **exactly** as
before. F10 Audio on file select still commits via D361's game-thread
queue; test both fresh and existing EEPROM without altering the user's
save (backup/restore for probes).
- With overlay closed, append no panel DL and retain existing golden frame
hashes (unless FPS display is explicitly enabled). Run `./build-pc.sh
ntsc-final`, link/duplicate-symbol checks, front-end + stage smoke,
`GE_WSPROBE_F10FRONT` and targeted live playtest. Log the result in
`docs/dev/findings.md` after implementation, not in advance.
## 5. Explicit non-goals
No fullscreen 3D folder in gameplay, changes to the N64 watch, new config
keys, row wording/value changes, save-format changes, controller remapping,
new persistent assets, or `src/game` behavioral edits. The front-end PC
Options screen is a **visual reference**, not part of the first styling
patch; harmonizing its tiny decorative details is a later optional pass.
+31 -6
View File
@@ -73,6 +73,12 @@ Sequencing follows M-139's R → Q → F order, split into four phases below.
| D314/D315 | F10 flicker (user-deprioritized) + main-vs-in-game menu scaling | D315 deferred from v0.3.0; bigger design question — lands naturally with the overlay work. |
| D238 | Mouse sensitivity rework (master sens, RMB aim sens, Y-gain parity) | Partly superseded: aim modes folded (D337, N64 default via PD integration; Centred (PC) opt-in), Aim range PC/N64 (D338). Remaining: sensitivity feel tuning. |
| D239 | Click-to-lock parity: delete always-grab mode 0 + config key | Small; closes D192 by deletion. |
| GEPD controls preset | New opt-in key-layout option ("Controls: FPS (default) / GEPD") reproducing the 1964 GEPD scheme: Q=A (accept/next-weapon), E=Use (B), **R=dedicated reload**, **Ctrl=crouch** (hold or toggle mode); M1=fire / M2=aim / wheel=weapon-cycle / arrows=stick all already exist. Implementation = D214 bind-string presets (`Input.Layout` enum writing preset strings into `g_bindStr`, per-user ini override preserved) + two new port-layer actions (IA_RELOAD emits **B** — reload is the B button in GE: `lv.c:796` `bond_pressed_reload_activate()` → `attempt_reload_item_in_hand()`, so a dedicated key needs no ROM hack and zero game-code changes; IA_CROUCH emits B held — crouch is B, same as the pad layout `input.c:1477–1481` — or a latched toggle). **Wrinkle (decided 2026-09-27): the preset leaves LeanLeft unbound** (its default `Q`, `input.c:885`, would otherwise make GEPD's Q=Action emit A+L; 1964 has no lean key, so the faithful layout drops it — rebindable via per-key override; FPS layout keeps Q). Small, `input.c` + overlay row, OFF default. See `GEPORT-REFERENCE-DEEPDIVE.md` §7 and `MODERN-OPTIONS-PLAN.md` (M3). |
| Modern options wave (parity set, 2026-09-27) | One opt-in "Modern" section in the F10/PC options page (`GE.` ini namespace, unknown keys ignored, all rows **default-off / N64-original**): (a) **crosshair on/off + color** (N64 default: always-on white; tint/hide at the HUD draw site); (b) **low-end perf preset** (FpsCap 30 / AA off / render-scale — the D339/#92 follow-up); (c) **GE+ gameplay toggles, clean subset**: disable knockback, disable
hitstun, damage sound, endless death cam (damage flash already shipped
as D232 `Game.NoHitFlash`) — each a small `#ifdef PORT` hook point;
rule-2 flag per feature, port-side default OFF; see `GEPORT-REFERENCE-DEEPDIVE.md`
§2.1 for the full upstream list); (d) **AllUnlocked preservation proof**: verify untoggling keeps progress (D257 read-time patch design should already guarantee it — evidence, not code). (F12 screenshot → PNG dropped from this wave 2026-09-27 — the dev PPM dump stays, the PNG upgrade is parked.) Total ≈ 2 sessions; lands in Phase 3 as one wave. |
| D226 | Player-adjustable HUD scale (ammo counter, pickup text, dialogue) | **DONE 2026-09-24 (`30720354`)**: Game.HudScale 75–150% (user-verified), fast3d rect scaling about anchors, dialogue/bottom width-capped. |
| Rumble (D224) | Wire `osMotor*` → `SDL_GameControllerRumble` (PD precedent exists) | Deprioritized M-87; pick up if gamepad support is in scope for v0.4.0 — user call. |
| Per-pad tuning / hot-plug | PD incremental hot-plug + remembered seats; deadzone/scale/rumble per pad | Medium; real-controller users. |
@@ -190,15 +196,25 @@ sweep after each landing).
5. Long-idle soak test (both platforms) as the stability acceptance bar.
### Phase 3 — Improvements / QoL (only after Phases 1–2 are green)
Order by user-visible value:
1. **Native widescreen** (letterbox/center instead of stretch) — the biggest
remaining "feels wrong" item; decide the CenterHUD G-class sign-off first.
2. **F10 overlay wave: D237 (wheel + categories + more settings) + D314/D315.**
Order by user-visible value (2026-09-27 refresh — several rows since DONE, marked):
1. ~~**Native widescreen**~~ — **DONE 2026-09-23** (D334/D335; playtest sign-off owed).
2. ~~**F10 overlay wave: D237 + D314/D315**~~ — D237 **DONE 2026-09-23**; D314/D315 still open (user-deprioritized; lands with further overlay work).
3. **Input feel: D238 sensitivity rework, D239 delete always-grab, window
HiDpi/center; rumble + per-pad tuning if gamepad is in scope (user call).**
4. **D226 HUD scale** (F10 slider candidate alongside FovScale).
4. ~~**D226 HUD scale**~~ — **DONE 2026-09-24**.
5. Unlocked FPS: re-measure Phase 0 against the post-D248/D250 baseline and
decide whether v0.4.0 or v0.5.0.
6. **Modern options wave** (Bucket C "parity set": crosshair on/off+color,
low-end perf preset, GE+ gameplay toggles subset, AllUnlocked
preservation proof, GEPD key-layout preset — F12 screenshot dropped
2026-09-27) — one opt-in
section, all rows default-off/N64-original. ≈ 2 sessions total (damage
flash was already D232; F12 screenshot dropped 2026-09-27); the
user-facing answer to "does it have the modern options". Per-item
hook points, effort, and rule-2 sign-off list: local
`MODERN-OPTIONS-PLAN.md` (M1–M7, M6 parked; zero sign-off: M1/M3/M5/M7,
one each: M2 + M4's four toggles — M4.3 is the shipped D232 NoHitFlash —
batched review).
### Phase 4 — Release ritual
1. `./build-pc.sh ntsc-final` clean; `/linkcheck`; full 21-level
@@ -457,9 +473,18 @@ Checklist beyond the normal play:
you see it, then share the `D303:` log lines from around that moment —
each line carries the RDP state of a candidate quad and will identify the
spurious draw call's source.
18. **AllUnlocked preservation (M7)**: with the new tree — enable
AllUnlocked, play two missions, toggle it OFF in the Watch options,
continue a third mission: objectives/saves must persist (D257
read-time patch design; evidence for the findings entry — failure is
its own D3xx). Also the modern-toggles A/Bs when M2/M4 land (see
`MODERN-OPTIONS-PLAN.md` per-item verification).
## Conventions reminder
- One findings entry per investigation; next labels after **D322**.
- One findings entry per investigation; the index tail moves constantly —
it ended at **D370** as of 2026-09-27 (the F10 drag entry), so new
labels start **D371+** (the old "after D322" note is long stale; always
confirm the tail of `findings-index.csv` before filing).
- Fidelity fixes: port-layer or documented A1/ABI exception only; genuine
behavioral differences need the rule-2 sign-off (`docs/dev-process.md`).
- Every subagent reads `docs/porting-notes.md` first and appends to it.
+11
View File
@@ -236,3 +236,14 @@ D355,FIXED,F10/options Music slider inaudible in-stage:,"FIXED (port-only, port/
D356,FIXED,"Settings regroup: Turok-style pages renamed to functional sections (INPUT/GAMEPLAY/GRAPHICS/AUDIO/VIDEO) with PD-style ""(File N)"" scoping annotations, the redu…","FIXED (port-only, port/src/optionsoverlay.{h,c} + port/src/watchsettings.{h,c} + port/src/frontoptions.c; plan docs/dev/D356-SETTINGS-REGROUP-PLAN.md):"
D358,FIXED,D356 level-1 overlap:,"FIXED (port-only, port/src/frontoptions.c):"
D359,PARTIAL,"Settings UI file terminology settled on the end-user term ""Profile"":","LANDED (port-only, frontoptions.c + optionsoverlay.c + comments):"
D360,OPEN,F10 INPUT heading scrolled away; F10 navigation and distance defaults (2026-09-27).,IMPLEMENTED (port-only):
D361,FIXED,Main-menu F10 Audio freezes the game:,"FIXED (port-only, port/src/watchsettings.c + F10 probe in optionsoverlay.c):"
D362,CLOSED,F10 GoldenEye dossier-style visual refresh (2026-09-27).,CLOSED (superseded by D363 after user playtest):
D363,FIXED,F10 return to a dark overlay with the N64 watch's green/Bank Gothic visual language (2026-09-27).,"FIXED (palette/font user-approved, 2026-09-27); D364 follows up on profile tags, click alignment and slider calibration."
D364,FIXED,Settings UI feedback:,FIXED (user mostly accepted; D365 follows up on annotation size and click targets).
D365,OPEN,F10 annotation hierarchy and visible mouse change targets (2026-09-27).,IMPLEMENTED (optionsoverlay.c):
D366,PARTIAL,Input calibration label:,PARTIAL: label changed in both UIs; numeric parity with external GEPD bundle needs its actual settings before changing input defaults.
D367,?,F10 full-width control boxes misaligned with their contents (2026-09-27).,SUPERSEDED by D368 after user playtest:
D368,?,Simplify F10 click targets:,"INPUT RULE KEPT; tinted strips user-rejected, removed in D369."
D369,FIXED,Remove F10 row boxes/strips entirely (2026-09-27).,FIXED (awaiting live acceptance):
D370,PARTIAL,F10 distance/volume drags hurt frame rate (2026-09-27).,PARTIAL (user live test):
1 # GENERATED by tools_pc/gen_findings_index.py -- do not hand-edit.
236 D356
237 D358
238 D359
239 D360
240 D361
241 D362
242 D363
243 D364
244 D365
245 D366
246 D367
247 D368
248 D369
249 D370
+312
View File
@@ -644,6 +644,17 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D356 | **Settings regroup: Turok-style pages renamed to functional sections (INPUT/GAMEPLAY/GRAPHICS/AUDIO/VIDEO) with PD-style "(File N)" scoping annotations, the redundant N64-watch rows (`Bond.Look`, `Bond.AimControl`) off the menu surface, and a real per-section Reset-to-defaults (two-step arm->confirm, watch rows to BLANKSAVEDATA via the D352 commit path, ini rows to the port's C initializers; `__Resolution` a documented exclusion) replacing the Turok reset rows the PC build never honored (2026-09-27).** — full `## D356` entry at file tail | FIXED (port-only, `port/src/optionsoverlay.{h,c}` + `port/src/watchsettings.{h,c}` + `port/src/frontoptions.c`; plan `docs/dev/D356-SETTINGS-REGROUP-PLAN.md`): 5 sections all below MAX_PROWS, hidden rows D181/D216-style (keys + watch paths stay live), edge-triggered reset with 3 s arm window + maintain/clear disarm, GE_WSPROBE_RESET front + in-stage probes headless-verified (all sections failures=0, scope isolation OK, saved bytes 0xFF), GE_WSPROBE/GE_WSPROBE_FRONT regressions clean. |
| D358 | **D356 level-1 overlap: the front options save-file row (item 0) painted under the first content row, and `s_hl` (item-numbered) was indexed straight into `s_rowIdx` (content-numbered) -- wrong-row adjusts, a dead last row, a one-past read, wrong highlight (2026-09-27).** — full `## D358` entry at file tail | FIXED (port-only, `port/src/frontoptions.c`): content rows draw at `rowY(k+1)`; all `s_hl` -> `s_rowIdx` uses take `s_hl-1`; A-press guards `s_hl >= 1 && s_hl <= s_rowN`; hit-test/cursor untouched (already item-numbered). Companion: "(save)" tag -> "(profile)". |
| D359 | **Settings UI file terminology settled on the end-user term "Profile": the screen mixed five terms ("Save file"/"File N"/"(profile)"/"Select file"/"(no file)"), and the manual's "game file" reads as the program's own files in modern PC usage (2026-09-27).** — full `## D359` entry at file tail | LANDED (port-only, `frontoptions.c` + `optionsoverlay.c` + comments): top row `Profile`/`N`, annotation `(Profile N)`/`(none)`, per-file row tag `(per profile)`, F10 value `Select a profile`; identifiers/ini keys unchanged (display-layer only). Manual "game file" -> "profile" sync TODO (port-owned doc, not in repo). |
| D360 | **F10 INPUT heading scrolled away; F10 navigation and distance defaults (2026-09-27).** — full `## D360` entry at file tail | IMPLEMENTED (port-only): F10 root category list + per-section Back; distance sliders normalized to 0–100, default 50/100 (250% authored distance), 2x MSAA default. Compiled and linked to a separate test binary (live game locked main executable); manual playtest owed. |
| D361 | **Main-menu F10 Audio freezes the game: EEPROM save from joyPoll deadlocks waiting for its own poll ack (2026-09-27).** — full `## D361` entry at file tail | FIXED (port-only, `port/src/watchsettings.c` + F10 probe in `optionsoverlay.c`): queue front F10 save edits to game thread; actual poll-thread Music+FX commits tested with existing and fresh EEPROM, orderly quit, user's ini/save restored. |
| D362 | **F10 GoldenEye dossier-style visual refresh (2026-09-27).** — full `## D362` entry at file tail | CLOSED (superseded by D363 after user playtest): paper/Zurich/gold look rejected. The pinned section heading and shared layout/hit geometry remain. |
| D363 | **F10 return to a dark overlay with the N64 watch's green/Bank Gothic visual language (2026-09-27).** — full `## D363` entry at file tail | FIXED (palette/font user-approved, 2026-09-27); D364 follows up on profile tags, click alignment and slider calibration. |
| D364 | **Settings UI feedback: replace P legend; F10 slider click band misses drawn bar; input defaults visually off-centre (2026-09-27).** — full `## D364` entry at file tail | FIXED (user mostly accepted; D365 follows up on annotation size and click targets). |
| D365 | **F10 annotation hierarchy and visible mouse change targets (2026-09-27).** — full `## D365` entry at file tail | IMPLEMENTED (`optionsoverlay.c`): dim Bank Gothic profile annotation (not oversized Zurich); `CONTROLS:` Zurich heading, smaller Bank Gothic instructions; boxed right-hand controls + hover and matching bounded click x. NTSC build/link/stage capture pass; live click assessment owed. |
| D366 | **Input calibration label: call 50 the default, not original (2026-09-27).** — full `## D366` entry at file tail | PARTIAL: label changed in both UIs; numeric parity with external GEPD bundle needs its actual settings before changing input defaults. Built, stage tested in D367; user playtest owed. |
| D367 | **F10 full-width control boxes misaligned with their contents (2026-09-27).** — full `## D367` entry at file tail | SUPERSEDED by D368 after user playtest: per-value boxes remained confusing. |
| D368 | **Simplify F10 click targets: setting name selects, the rest changes (2026-09-27).** — full `## D368` entry at file tail | INPUT RULE KEPT; tinted strips user-rejected, removed in D369. |
| D369 | **Remove F10 row boxes/strips entirely (2026-09-27).** — full `## D369` entry at file tail | FIXED (awaiting live acceptance): no row backgrounds, control rectangles or hover paint; selected setting distinguished by brighter text, slider tracks remain. Input rule from D368 unchanged. |
| D370 | **F10 distance/volume drags hurt frame rate (2026-09-27).** — full `## D370` entry at file tail | PARTIAL (user live test): mostly improved; rapid spam can still lower FPS. Unchanged-detent/audio and Draw/LOD reapply fixed; other image sliders still request full video pass (live log shows frequent FOV passes). No further churn without focused repro. |
Phase 2 replaced the Phase-1 demo loop with the real `mainproc()` on real OS
threads, compiled GE's real `src/sched.c`, and brought in PD's fast3d software
@@ -13997,3 +14008,304 @@ display-layer concern only (principle 3).
**TODO:** update the instruction manual's "game file" to "profile"
(port-owned doc, not in this repo).
## D360 — F10 category navigation and modern-display distance defaults (2026-09-27)
**Reported:** F10's INPUT header was offscreen above Mouse sensitivity when
scrolling; the long flat list was hard to navigate. Draw/LOD distance auto
switches obscured the controls and N64-scale pop-in looked like a port bug.
4x default MSAA was too expensive for low-end hardware.
**Fix (port-only):** F10 opens on a five-category list, and entering a
category shows its header (with Back) and settings together. Keyboard,
controller, mouse and wheel all use the same per-page list. ESC backs out of
a section, then closes from the category list; F10/Start/X still close.
Front-end PC Options already had category pages and shares the row table.
Removed AutoFov controls from both menus (ini keys remain for legacy files),
and exposed both distance sliders at all times. Stored values remain percent
of authored distance; the UI displays 0–100, where 50/100 maps to 250%.
Fresh and SteamOS defaults are 250% draw and LOD distance, 2x MSAA. Reset
uses the same new defaults. Existing ini settings are preserved; old LOD
values below the menu minimum (100%) can still be edited via ini. Note:
these higher distances increase visible geometry/pool demand; test on
open levels and low-end GPUs before claiming performance parity.
**Verification:** `git diff --check` clean. `build-pc.sh ntsc-final`
initially failed because GCC could not create temporary files in
`C:\Windows\`; configuring C/C++ with `-pipe` built all 248 objects.
The existing executable was locked by a running `ge007.x86_64` process,
so the same linker response file was linked to
`scratch/cc-tmp/ge007-check.exe` successfully. No live game was interrupted.
Manual mouse/pad/ESC, reset, and 50/100 rendering/perf checks are owed.
## D361 — F10 Audio on the main menu locks up: self-deadlock in EEPROM poll gate (2026-09-27)
**User repro:** fresh v0.4.0 playtest, change an AUDIO slider from F10
on the main menu → game locks (not merely an inaudible volume change).
**Exact chain:** F10 input is processed inside `inputComputePad()` called
by `osContStartReadData()` in `joyPoll()` (`src/joy.c:500`). D354 routed
front-context watch edits through `watchSettingsSet()` → `saveFrontField()`
on that same poll thread. Both `fileGamePakProbe()` and `fileWriteSave()` call
`joyGamePakProbe/LongWrite()` → `joyDisablePoll()` → blocking receive on
`g_ContDisablePollReceiveMessageQueue`. Only `joyPoll()` can send the
acknowledgement (`src/joy.c:434`), but it is itself blocked inside the
F10 edit: deterministic self-deadlock. D354's claim that one settings
surface meant this thread's writes were safe was incorrect; serialization
between editors does not make the controller-poll handshake re-entrant.
**Fix (port-only):** front F10 writes now coalesce in a small locked
folder/field queue. `watchSettingsGameTick()` drains commits on the game
thread before its non-stage early return and runs `saveFrontField()` there,
with no lock held across EEPROM I/O. The on-screen value is staged before
enqueue for immediate feedback, then cleared only after the matching commit.
The separate stage queue and the direct front options screen path retain
their prior behavior. `GE_WSPROBE_F10FRONT=1` is an opt-in regression probe
called from F10's actual controller-poll input path at file select (once,
after a valid save is available), committing Music+FX to 4096.
**Verified:** NTSC incremental build/link succeeded. Native Windows test
with `GE_OPTIONSOVERLAY=1`, `Game.SkipIntro=1` and the poll-thread probe
logged the queue plus both Music/FX field persist events and exited via
`GE_QUITFRAME=700` (with existing EEPROM **and** absent EEPROM on boot).
The pre-existing game-thread `GE_WSPROBE_FRONT=120` front-path regression
also persisted Music 255→32 and quit normally. The user's ini and EEPROM
were copied aside and restored byte-identically after each run. Manual
mouse slider/section-reset and stage transition checks remain owed.
## D362 — F10 GoldenEye dossier-style visual refresh (2026-09-27)
**Request:** restyle F10 to match GoldenEye, following
`docs/dev/F10-GE-STYLE-PLAN.md`. Existing front Options already uses the
in-game dossier; in-stage F10 needs a lighter port-owned 2D equivalent.
**Implementation (port-only):** replace the blue/black panel with a dark
scene scrim and warm paper card/shadow/rules, Zurich Bold menu ink (Bank
Gothic fallback during early font loading), MI6 gold masthead, dark-red
active values and slider fills/knobs, numbered GE-style category labels,
faint black selected-row highlights. The active section's Back/title/Profile
band stays pinned while content scrolls, so INPUT never disappears above
Mouse sensitivity. A short `P` gutter marker and footer legend retain
per-profile scoping without the old `(per profile)` label/value collision
at 320px. One `OvLayout` drives render, max rows, slider/drag coordinates,
mouse row-hit bands and close box. No config, input binding, save format,
N64 game-code, or F10 audio queue changes. `GE_OPTIONSOVERLAY=2..6`
optionally auto-opens a particular section for deterministic screenshots
(`=1` remains the category root).
**Verification:** NTSC compile/link clean; native-Windows `GE_PCDUMP`
front-end root and GRAPHICS capture plus 320x240 stage GRAPHICS capture
(no crash/overflow; orderly `GE_QUITFRAME` exit). Captures:
`scratch/d362-test/` (local, not distributed). User ini and EEPROM restored
byte-identically after each run. A final tiny title/footer polish rebuild
compiled, but the running playtest held `build-pc/ge007.x86_64.exe` open;
linked identical objects to `scratch/d362-test/ge007-d362.exe`, and the
local `scratch/playtest_v040.bat` installed that binary on the next
closed-game launch (guards against a concurrent game process; installed exe
size/timestamp match the staged build). Live human
review of palette, label fit, mouse clicks/drag/wheel, controller focus,
back/close, longest GRAPHICS labels and the F10 Audio regression is owed.
**User follow-up:** dossier/paper styling rejected; see D363 for the dark,
watch-green successor. D362 is retained as the design/iteration record.
## D363 — F10 returns to a dark overlay, restyled after GE's green watch (2026-09-27)
**User feedback on D362:** "make it more like how it was but use the watch
style as a reference — green, that other font etc." The watch's actual
options pages (`src/game/options.c:3524+`, `:3825+`) use Bank Gothic and
mint/bright green ink (`0xA0FFA0F0` selected, muted green unselected).
The paper card, Zurich Bold, gold, red, numbered categories and dossier
branding from D362 were not the desired direction.
**Fix (port-only):** restore the original F10's simple dark translucent
panel and full-screen dim; use the existing Bank Gothic font for all rows,
subdued green for ordinary text and bright watch green for selection,
active values and slider knobs/fill. The `PC OPTIONS` title and close `X`
replace MI6/CLOSE; category names return to their uppercase row labels.
Keep D360's two-level navigation and D362's shared layout/hit geometry,
scrolling and pinned section heading; no setting behavior or save changes.
The mixed-scope profile marker stays short to avoid 320px overlap.
**Verification:** NTSC build/link clean. `GE_OPTIONSOVERLAY=4`,
`GE_PCDUMP=160-160` with native Windows `GE_QUITFRAME=170` passed in both
front/menu and `-level_09` stage contexts at 640x480: dark panel and green
pixels present (front/stage captures in `scratch/d363-test/`), no errors,
orderly exit. User ini and EEPROM restored byte-identically after both.
Live review of colour, text, click/drag/wheel, controller, ESC/close and
F10 Audio remains owed.
**User follow-up:** palette/font approved, but P shorthand, low-contrast
legend, slider mouse hit position and off-centre input defaults need work;
see D364.
## D364 — Profile scope, F10 slider hitbox and calibrated input displays (2026-09-27)
**Reported:** user likes D363's palette but not `P` / `P = PROFILE`;
controls legend reads like setting text; clicking the visible F10 slider
requires aiming above the bar; Input defaults such as deadzone and trigger
show ~23% rather than a visually centred 50/100 or 5/10.
**Diagnosis:** the F10 bar was at `rowY + 10..12` (knob `+8..14`), but
`overlayRowAtY` assigns the row only within `rowY - 8..+8`: the bar/knob
landed in the NEXT row's hit band. The input values were physically correct
(raw `MouseSensitivity=100` of 1..500; `PadDeadzone=7000` of 0..30000,
~21% full-stick travel; `PadTriggerPct=23` of 1..99), but the UI treated
them as linear full-range sliders rather than calibrated defaults. AUDIO's
`Bond.Music`/`Bond.FX` rows were watch-backed but lacked `.saveScoped`, so
the promised `(Profile N)` title was missing despite every Audio row being
per-profile.
**Fix (port-only):** move F10 slider bar to `rowY+3..5` and knob to
`rowY+1..7`, both entirely inside the row's `-8..+8` click band. The one
shared slider-bar geometry still drives dragging. Give the control legend
its own dark inset strip with muted-grey Zurich text (Bank Gothic remains
for SETTINGS); likewise use a separate font/colour for scope notes. Remove
`P`/legend. Tag each saved Gameplay toggle `(profile)` beside its label
when measured space permits; Audio is entirely per-profile, so its title
now carries `(Profile N)` (both UIs) and no per-row tags. The front dossier
also suppresses redundant inline Audio tags. Input's three calibrated
sliders now display 0–100, mapping each *unchanged* raw default to 50/100
via a two-segment monotonic map preserving raw minimum and maximum; bars,
mouse drags and the shared front options screen use that same map. A
`(50 = original)` note explains the scale. Other sliders (audio %, texture
filter x, FOV/HUD %) keep their physical units and authored defaults.
Reset still writes the original raw defaults, config/ini values are unchanged,
and input sensitivity/deadzone/trigger behavior is untouched.
**Verification:** NTSC build/link clean. Native-Windows `GE_OPTIONSOVERLAY=2`
+ `-level_09` stage screenshot at 640x480 and orderly `GE_QUITFRAME=180`
pass, with the user ini/EEPROM restored byte-identically after the run.
Mouse click/drag on real 4:3/16:9 front/stage, reset and visible tooltip
fit still need an interactive user pass. User accepted most of D364 but
requested smaller profile annotation, a `Controls:` heading with smaller
instructions, and a visible mouse-change target; see D365.
## D365 — F10 annotations and bounded mouse-change controls (2026-09-27)
**Reported:** `(profile)` is visibly larger than its setting label; the
Controls legend should read `Controls:` with smaller following instructions;
it isn't visually clear that a label click *selects* but the right column
*changes* a setting.
**Fix:** Bank Gothic (the smaller watch font already used for row labels)
now renders dim profile tags and section scope notes instead of the larger
Zurich Bold. The footer's `CONTROLS:` heading keeps Zurich Bold, but its
instructions use smaller, dim Bank Gothic, including `BOX: CHANGE` within
sections. Draw subtle green-bordered dark control boxes around every section
row's right-hand interactive area, brightening the hovered box without
moving keyboard selection. Restrict left/right mouse changes to the same
bounded x region; label clicks still select only. Coordinates are mapped
through `gfx_get_ui_screen_rect` for hover as for input, preserving the
safe-area crop behavior (D316). No game logic or saved data touched.
**Verification:** NTSC compile/link and 640x480 `GE_OPTIONSOVERLAY=2`
`-level_09` frame-160 capture with clean frame-180 quit; ini and EEPROM
restored byte-identically after testing. During compilation the user's
existing game process held the exe, so it was first linked to a staged
scratch path rather than overwritten; final build linked directly after
that process exited. Mouse hover/click in a live window is still owed.
## D366 — Input slider calibration: “default,” not “original” (2026-09-27)
**Request:** user prefers the GEPD bundle as the standard for input and
wants the `(50 = original)` note to read `(50 = default)`.
**Fix:** changed both settings UIs' Input-header text to `(50 = default)`.
`calibratedDefault()` still maps the port's current *real* defaults
(`MouseSensitivity=100`, `PadDeadzone=7000`, `PadTriggerPct=23`) to 50/100,
and `kResetDefaults` agrees with `input.c`. No live config or save edited.
**Caveat:** GEPD's emulator bundle is an external reference; this checkout
has a stub in `reference/mouse-injector/` and its `GEPD-INPUT-PLAN.md` records
its camera aim formulas, but neither has an authoritative bundle controller
config for all three numbers. The port's 38/50 per-mode mouse speeds were
user-calibrated for its own FOV. Don't claim numeric parity with the GEPD
bundle or re-tune default input feel without the user's bundle configuration.
**Verification:** NTSC compile and staged link succeed. The active user's
playtest held `build-pc/ge007.x86_64.exe`, so the new binary was linked to
`scratch/d366-test/` and the local v040 launcher installs it only after the
running game exits. No stage smoke test while the user's save is active. The user later exited;
D367 includes the subsequent native stage smoke test of both changes.
## D367 — F10 control frames aligned with their actual clickable contents (2026-09-27)
**Reported:** D365's full-width rectangles do not align with their text
contents. Root cause: every row used a fixed `[barX0, right-7)` box despite
right-aligned toggles/enum text near `right-12`, slider bars ending much
earlier at `barX1`, and reset actions having their button in the *label*
column (empty value until armed). This advertised empty space as clickable
and left the reset's real target unframed.
**Fix:** `overlayControlSpan()` now calculates the actual button region per
row: tight around slider tracks, around measured right-aligned values, or
around the reset label; non-interactive/unavailable slider rows get no box.
Both mouse buttons and hover use that same geometry, so moving the mouse
only highlights a genuinely clickable area. The narrower border fits the
Bank Gothic text's vertical footprint. Label clicks on ordinary settings
still only select; clicking the framed reset label invokes its existing
two-step confirmation. No game logic or config/default value changes.
**Verification:** NTSC compile/link passed, native 640x480
`GE_OPTIONSOVERLAY=2 -level_09` stage capture and orderly frame-180 exit;
ini/EEPROM restored byte-for-byte. Mouse click/hover and confirmation remain
to be feel-checked live. User's immediate playtest found remaining boxes
wrong; replaced by the simpler D368 rule.
## D368 — F10: name selects, right-of-name changes (2026-09-27)
**User decision:** stop trying to frame each differently sized value; all
of the row except the setting name should change it. D367's boxed controls
were still misleading in a live test.
**Fix (port-only):** `overlayControlSpan` now starts after the measured
Bank Gothic setting name (capped at its label-column clipping edge) and
extends to the panel's right edge. It is used by mouse hover, left/right
click and a single subtly tinted strip with a thin left divider; the
per-value borders are gone. Clicking a name still focuses without changing.
A slider click on its track positions/drags; clicking elsewhere to the right
of its name changes it by one step instead of snapping to the minimum or
maximum. Reset is an action, so its whole row activates the existing
confirmation. The footer now says `RIGHT: CHANGE`. No config/save or game
logic changes. NTSC build/link passes; live mouse check still owed.
## D369 — Remove F10 per-row paint (2026-09-27)
User still saw boxes in D368 because the tinted per-row change strips and
selected-row rectangles were still painted. Removed **all** of those from
`optionsOverlayEmit()` (including hover paint). Selected text remains
brighter, sliders retain only their track and knob, and the existing dark
panel/Controls footer remain. Mouse hit behavior from D368 is unchanged.
NTSC compile and staged link pass; a running playtest still holds the old
exe, so the local launcher will install `scratch/d369-test/ge007-d369.exe`
only after the game exits. No save/ini touched.
## D370 — Avoid redundant work during F10 slider drags (2026-09-27)
**Reported:** dragging Draw/LOD distance, Music or FX volume drops FPS.
**Diagnosis:** `sliderSetFromX` runs on every controller poll while LMB is
held, including repeated polls over the *same snapped value*. `rowSetCommit`
then re-enqueues watch audio updates and, for *any* `Video.*` key, requests a
`videoStartFrame` live-config pass: `set_swap_interval`, FPS cap, texture
filter, image state and a log line. Draw/LOD multipliers are already read
straight from their config pointers by the render path, so no such pass is
needed. The active playtest log has hundreds of `video: live config applied`
lines and multiple watch-setting persists; log alone does not isolate all
of those calls to one knob. Physically increasing Draw/LOD can independently
increase rendering load, which this fix will not hide.
**Fix (port-only `optionsoverlay.c`):** early-return before live-apply/queue
when a snapped value has not changed (including queued watch settings); held
mouse polls no longer repeat the same audio setter or GL state work. Retain
slider-release `watchSettingsCommit` so a drag persists exactly once. Exempt
only `Video.DrawDistance` and `Video.LodDistance` from
`videoRequestLiveConfig`; all other Video keys retain their old live-apply
semantics. Audio updates still preview live for genuinely changed detents.
No user config/save or game code edited. NTSC compile + staged link passed;
active Windows game initially held the executable; the local launcher
installed the staged binary on the user's next safe launch (now running).
Live FPS retest (ideally compare dragging
Music/FX while paused vs simply raising Draw/LOD values) owed.
**User playtest:** "it can still drop it down if you spam it but mostly good."
Residual not isolated: the latest playtest log shows repeated full video
config passes while changing FOV (not Draw/LOD) and several watch EEPROM
persists; sustained high Draw/LOD also increases actual GPU work. Parked as
polish until a focused repro identifies which slider/spam pattern dominates.