maniator / maniator/verticopolis

[P3] Interaction state is scattered across five sources, so derived UI state can be computed somewhere skippable

Open
#716 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
5
Forks
1
PR merge metrics
No merged PRs in 30d

Description

Deferred from the /gds-code-review of the desktop command seam (PR #715).

Five different places answer "is the game interactable right now": app.shownChoice, app.shownUpdate, #modal.open, #splash existing, and #crash-screen existing. GameApp carries 27 mutable public fields that friend-modules write directly.

That scatter caused a real defect found in this review. The host-command availability push sat below runFrame's early return on app.shownChoice || app.shownUpdate, so the desktop shell was told "everything is available" in exactly the state where #modal.open guaranteed every command would be refused. Two of the five sources disagreeing, in the one state that mattered. Fixed at the instance in #715; this row is the class.

There are also three hand-rolled computed-selector-with-change-detection implementations: UI.paletteScanKey, lastUiUpdate, and the new lastAvailabilityKey.

Party ruling (2026-07-29): no state management library. Three app-specific reasons:

  1. src/engine/ is deliberately framework-free and Classic is byte-locked, so a store creeping into simulation state risks golden masters for no gain. None of the pain is in sim.
  2. The adoptSim design depends on friend-modules re-reading app.sim per call, which is the property a reactive store would most want to "fix".
  3. All five disagreeing sources are UI chrome state. sim, engine, audio, and grid are fine.

Fix shape: one module owning interaction state with a change notification, replacing the DOM queries in hostCommands.refusalFor and the 6 Hz poll in tickHostCommands, and collapsing the three dirty-gates into one implementation.

Only worth doing if it owns all five sources. Owning two would add a sixth source rather than remove five, which is why it was kept out of #715. Needs a design doc first per the deliberate-addition rule.

No engine, save, or gameplay impact. /bmad-code-review.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the interaction sources named in the issue—app.shownChoice, app.shownUpdate, #modal.open, #splash, and #crash-screen—and trace hostCommands.refusalFor, tickHostCommands, UI.paletteScanKey, lastUiUpdate, and lastAvailabilityKey. Begin with the required design doc; done means one module owns all five sources, not two, with unified change notification and dirty-gate behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
desktop, frontend
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.