Commit Graph
24 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.6 cbcfeccd67 fix(ui): PR #131 review round 1 — retire starchart, harden registry
Addresses blocker comments from PR review:

- Delete star_map.gd and star_map.tscn — dead implant/map/starchart
  HudGroups registration that should have landed with the atlas
  unification (D-191 criterion 1)
- Remove test_star_map_is_accessible_from_insert_ui and
  test_star_map_scene_exists from test_sprint30.gd — D-191 supersedes
  the insert-UI accessibility pattern
- ImplantRegistry._scan() now detects default_key collisions
  (first-wins with push_warning) and validates default_mode against
  HudGroups.Mode enum (skip + warn on invalid)

star_map_data.json remains — still used by atlas_app and
economics_app for system index lookups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 14:03:25 +02:00
jpmschweitzerandClaude Sonnet 4.6 bcb9245122 style(ui): gdformat implant_app.gd
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 13:18:37 +02:00
jpmschweitzerandClaude Sonnet 4.6 19848cd4f0 style(ui): gdformat atlas_app.gd
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 13:17:58 +02:00
jpmschweitzerandClaude Sonnet 4.6 df29d26d1e feat(ui): introduce ImplantApp pattern — base class, registry, atlas + economics refactor (#844, #824, #836)
Establishes the ImplantApp faux-mobile-OS architecture (D-191):

Foundation:
- ImplantAppManifest (Resource): @export vars for app_path, scene_path, default_key, default_mode, preserves_state
- ImplantNavStack (Node): push/pop/replace/reset_to_default, synchronous screen_changed signal
- ImplantApp (Control base class): absorbs HudGroups boilerplate; on_install/on_open/on_close/on_insert_deactivated lifecycle hooks
- ImplantRegistry (autoload): lazy-scans res://ui/implant/apps/*/app.tres; avoids autoload parse-order trap

Atlas app (replaces atlas_panel + atlas_reach_map + atlas_system_map + atlas_planet_map + root viewer files):
- apps/atlas/app.tres — manifest (implant/map, FULLSCREEN, key=M)
- apps/atlas/atlas_app.gd — coordinator; 4-screen nav via ImplantNavStack
- apps/atlas/screens/{reach,system,planet,regional}_screen.gd — enter/leave interface
- apps/atlas/{atlas_viewer,atlas_marker_overlay,atlas_overlay_bar}.gd — moved from root

Economics app (replaces economics_panel):
- apps/economics/app.tres — manifest (implant/economics, INSERT, key=N)
- apps/economics/economics_app.gd — thin shell delegating to OverviewScreen
- apps/economics/screens/overview_screen.gd — full panel logic, enter/leave interface

Wiring:
- project.godot: add ImplantRegistry autoload after HudGroups
- main.gd: registry-driven key toggle loop; rename atlas_panel→atlas_app, economics_panel→economics_app
- hud.tscn: swap to new scene paths; remove legacy StarMap node
- snapshot_consumers.gd: on_insert_deactivated() uniformly; rename vars
- hud_groups.gd: remove stale starchart compat comment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 13:16:56 +02:00
jpmschweitzerandClaude Sonnet 4.6 3613b22c8f style(ui): apply gdformat to atlas split files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:33:40 +02:00
jpmschweitzerandClaude Sonnet 4.6 03060ff2e1 refactor(ui): split atlas_panel.gd into 4 sub-widgets under 500 lines each
atlas_panel.gd exceeded gdlint's 1000-line limit after the REACH_MAP level
was added in #844. Split into:
  - atlas_panel.gd (298 lines)   — shell: HudGroups reg, level enum, nav, key handler, screen header
  - atlas_reach_map.gd (494)     — Level 0 REACH_MAP hop-ring view; emits enter_system
  - atlas_system_map.gd (495)    — Level 1/2 SYSTEM_PICKER + ORBITAL_DIAGRAM; emits enter_body
  - atlas_planet_map.gd (146)    — Level 3/4 BODY_ENTRY + HEIGHTMAP_VIEWER; emits back_to_viewer_body

Shell owns all level transitions. Sub-widgets emit signals, never call show_level().
All four pass gdlint with no warnings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:27:27 +02:00
jpmschweitzerandClaude Opus 4.6 a06646d810 feat(ui): unify star map and atlas into single implant/map chain (#844)
Per D-191, the atlas is the star map extended downward — not a separate
app. AtlasPanel now owns the full Reach → system → planet → heightmap
zoom hierarchy as a single HudGroups app (implant/map).

- Add REACH_MAP as Level 0 of AtlasPanel's zoom hierarchy; renumber the
  enum so higher index = deeper zoom
- Port hop-ring rendering (pan/zoom, system markers, hover/info, sector
  layout) from star_map.gd into AtlasPanel methods
- Change AtlasPanel.APP_PATH from "implant/map/atlas" to "implant/map"
- main.gd: KEY_M toggles unified atlas; KEY_A binding removed
- Symmetric nav: ORBITAL_DIAGRAM back goes to REACH_MAP (not
  SYSTEM_PICKER), matching the forward skip
- hud_groups.gd docstring documents the unified path and flags the
  legacy starchart path as kept-for-compat (retirement tracked in #852)

star_map.gd's HudGroups registration stays live but inert — no key
binding reaches it. Full retirement follows in #852 after a sprint of
soak on the unified panel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 11:52:15 +02:00
jpmschweitzer 22c17f1f15 style(ui): gdformat atlas implant files 2026-04-15 09:06:04 +02:00
jpmschweitzer 489aec48d8 style(ui): atlas review polish — guarded ids, stable keys, dead-code cleanup (#128)
10. Dropped the "no body data" fallback string in the picker panel — the
    generator always writes entry["bodies"], so the fallback was dead. Use
    the "—" convention the rest of the panel already follows.
12. Removed the autoload parse-order comment from AtlasPanel (it is
    scene-instanced, not an autoload, so the rule does not apply), and
    collapsed _build_heightmap_viewer to a direct AtlasViewer.new() —
    mirroring the rest of the file rather than dancing around a risk that
    is not real for this class.
13. AtlasMarkerOverlay._draw_cities now compares hover/selection by a
    stable _city_key() (name → city_id → pos → hash) instead of
    Dictionary.==, which was O(fields) per city per redraw. Preps the
    renderer for much larger city counts without a rewrite.
14. Orbital click/draw handlers guard against missing body_id /
    station_id by reading through str(dict.get(..., "")) and skipping
    empty ids. Matches the defensive style already used for parent_body_id
    and keeps a NULL id from crashing _draw_bodies / _handle_orbital_click.
2026-04-15 09:02:27 +02:00
jpmschweitzer f8b81e1fe7 refactor(ui): atlas review warnings — headers, public API, KEY_N, overlay source of truth (#128)
4. AtlasPanel and AtlasViewer now compose their title + hint from an
   ImplantHeader child rather than hand-rolling them via draw_string, so the
   D-169 "theme swap changes the implant hardware appearance" invariant
   holds end-to-end. _refresh_screen_header() drives content per level and
   on system navigation.

5. AtlasViewer exposes city_canvas_pos(), get_hovered_city(),
   get_selected_city(), and get_overlay_defs() as public API — the marker
   overlay no longer reaches into underscore-prefixed state, which is
   especially important because viewer is an untyped var in the overlay.

6. KEY_N now consumes unconditionally while the viewer is visible, and
   main.gd's global economics-monitor toggle is gated on
   !HudGroups.is_app_active("implant/map/atlas"). Previously pressing N
   without a selected city fell through and closed the fullscreen atlas as
   a side effect.

7. OVERLAY_DEFS lives in AtlasViewer as the single source of truth.
   AtlasOverlayBar reads the list via viewer.get_overlay_defs(), and
   AtlasViewer derives _overlay_visibility / _overlay_locked from the same
   table at _ready() — no more hand-maintained parallel lists, so the bar
   and the guard in set_overlay_visible can't drift.

8. AtlasOverlayBar drops `class_name`: it now loads via
   load("res://ui/implant/atlas_overlay_bar.gd") from AtlasViewer, the same
   pattern AtlasPanel uses for AtlasViewer. _init(viewer_ref = null) keeps
   the required-arg footgun off the editor's introspection path.

9. `star-map-data` make target added to regenerate
   client/data/star_map_data.json from systems.db + wiki, and
   `check-star-map` wired into pre-pr-validate + pre-pr-client so any
   commit that touches the generator (or any downstream systems.db change
   like server #839) fails pre-pr until the JSON is regenerated. The
   terrain_reference data-availability dependency is no longer tribal
   knowledge.

Also addresses review #15 (push_warning on unknown overlay id in
set_overlay_visible) and #16 (disabled always-on buttons drop handler
churn) as part of the same refactor.
2026-04-15 08:59:21 +02:00
jpmschweitzer 1328db3138 fix(ui): atlas review blockers — moon layout, stale grid dims, overlay schema (#128)
1. Moon placement on the orbital diagram divided by a hard-coded 4 — a gas
   giant with five or more moons would overlap satellites and make them
   unclickable. Count moons per parent and distribute them evenly.
2. AtlasViewer._load_markers seeded _grid_w/_grid_h from _tex_w/_tex_h
   before the terrain_reference null check, so opening a body with no
   heightmap after one that had a heightmap left the grid dimensions
   pointing at the previous texture and misplaced markers. Reset texture +
   grid dims to sentinel defaults at the top of _load_heightmap.
3. AtlasMarkerOverlay's three toggleable overlays (production_zones,
   shadow_economy, corp_presence) read markers.production_zones /
   markers.shadow_zones / markers.corp_presence — keys that don't exist in
   D-191 §8's markers schema, so toggling was a silent no-op. Derive them
   from cities[] instead: primary_function ∈ PRODUCTION_FUNCTIONS for
   production, absent Commission presence for shadow bands, Commission
   presence for corp dots. Follow-up ticket will formalise per-overlay
   arrays once the server schema lands.

Addresses PR #128 review blockers 1-3.
2026-04-15 08:47:14 +02:00
jpmschweitzer 9afd6b53d2 style(ui): wrap atlas long lines to satisfy gdlint 2026-04-15 08:31:40 +02:00
jpmschweitzer 9987eaad8a feat(ui): atlas overlay toggle bar — 9 MVP overlays + 2 locked (#836)
AtlasOverlayBar is an HBoxContainer docked top-right of the heightmap viewer
with 11 short-label buttons mapping to D-191 §7 / D-181 signal visibility:

  always-on (5)  TER INF NAM GAT POL — terrain, infrastructure, named
                 features, gate markers, political zones. Pinned on; clicks
                 are swallowed so the layers can't accidentally be disabled.
  toggleable (4) POP PRD SHD CRP — population density, production zones,
                 shadow economy, corporate presence. Reflect and mutate
                 viewer overlay state.
  locked (2)    STK BSL — stockpile_weeks, production_vs_baseline. Disabled
                 and greyed out with unlock-requirement tooltips, per D-181
                 semi-private/private tiers; kept in the bar so players see
                 that deeper data exists and is gated.

Each button writes through AtlasViewer.set_overlay_visible(), which is the
single entry point into the viewer's _overlay_visibility dict consumed by
AtlasMarkerOverlay._draw(). Locked overlays short-circuit in that setter.

Per D-191 criterion 6.
2026-04-15 08:27:30 +02:00
jpmschweitzer c33ac8921f feat(ui): atlas heightmap viewer — pan/zoom, marker overlay, city data panel (#835)
Adds Level.HEIGHTMAP_VIEWER to AtlasPanel. The viewer loads a body's
terrain_reference heightmap PNG, pairs it with markers.json (roads, rail, POIs,
cities, rivers/oceans/mountains), and renders markers in texture-space via an
AtlasMarkerOverlay Node2D child of a transformed canvas — pan = offset,
zoom = scale.

Pan/zoom is cursor-centred (wheel zooms under the mouse, drag pans), with a
fit-to-view reset on R. Empty markers.json state renders a bare heightmap;
missing terrain_reference shows a themed "terrain data pending (#839)" notice
instead of crashing.

City data sidebar rebuilds from the selected city: name, pop tier, function,
currency zone, Commission presence, shadow zone, gate distance. Pressing N on
a selected city emits economics_link_requested(system_id) — main.gd bridges
this to EconomicsPanel.select_system() + HudGroups.open_app("implant/economics")
as an insert overlay, satisfying the D-191 Phase 2/3 cross-panel integration.

The overlay renders all nine D-191 overlay layers off of per-overlay visibility
flags in AtlasViewer. Overlay toggling for the regional view (#836) plugs into
set_overlay_visible(); the five always-on layers (terrain, infrastructure,
named features, gate markers, political zones) draw by default, the four
toggleable layers draw from placeholder data, and the two locked layers
(stockpile_weeks, production_vs_baseline) remain off until unlocked.

Per D-191 criteria 1, 4, 5.
2026-04-15 08:22:01 +02:00
jpmschweitzer 760953aeba feat(ui): atlas implant panel — system picker, orbital diagram, body nav (#834)
3-level atlas navigation as an implant/map/atlas FULLSCREEN app (D-170 z=20):
system picker (◄ ► cycle, Enter opens orbital) → orbital diagram (star centre,
bodies grouped by orbit_index with moons sub-orbiting parents, stations as
markers, click-to-open body or mini station panel) → body entry (data sheet,
Enter stub for #835 heightmap viewer, Esc back). Composed from the ImplantPanel
component library (D-169).

Wires the panel into hud.tscn, adds an A-key toggle in main.gd, propagates
insert_state via snapshot_consumers. Extends generate-star-map-data.py to emit
per-system orbit_bodies + stations arrays (with currency_zone, atmosphere,
population, terrain_reference, etc.) from systems.db; star_map_data.json
regenerated deterministically.

Per D-191 §6, Phase 3.
2026-04-14 17:24:50 +02:00
jpmschweitzerandClaude Opus 4.6 e91bd1c7e4 fix(client): post-sprint polish — protocol v21, schedule workaround, UI fixes
- Bump client protocol version 20 → 21 to match server (#822)
- Fix render_priority parameter name (was _render_priority, unused prefix)
- Fix debug console type inference (var sub := → var sub: String =)
- Economics panel: add population row, improve key hint text
- Stance indicator: hide on gameplay_occluded (D-170 fullscreen apps)
- Remove 5 broken clothing items from manifest and delete their GLBs
  (boots_work, coveralls_basic, jacket_utility, pants_cargo, shirt_henley)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:00:40 +02:00
jpmschweitzerandClaude Opus 4.6 4d4dc2014d fix(ui): rebind economics panel toggle from E to N (#124 review R2)
E is claimed by InputMap "interact" action — InputMapper consumes
it before _unhandled_key_input. N is free, adjacent to M (star map),
reads as "Numbers" for the economics monitor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 14:25:07 +02:00
jpmschweitzerandClaude Opus 4.6 28d95c23a8 fix(ui): address PR #124 review — navigation, error handling, cleanup
- Economics panel: replace dead _gui_input LEFT/RIGHT with public
  navigate() method, wire [ ] keys in main.gd (avoids movement
  key conflict, fixes focus_mode=NONE issue)
- Debug console: add explicit effect guard in econ inject no-commodity
  branch so invalid effects don't fall to commodity-form error
- Snapshot consumer: null-clear GameState.economy_snapshot after
  consuming (matches one-shot consumer invariant)
- Star map: remove duplicate doc comment above set_insert_active()
- Generate script: remove stale comment, dead _WORKTREE_PARENT var,
  dead field extraction in parse_wiki_index, add try/except around
  DB queries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 14:03:49 +02:00
jpmschweitzerandClaude Opus 4.6 949d721eac feat(ui): economics monitor insert panel with placeholder data (#824)
New implant panel at implant/economics: system selector, 6-commodity
price table with trend indicators, GDP strip. Composed from D-169
component library. Ring buffer caches last 20 ticks per system.
Snapshot routing wired through snapshot_handler → GameState →
snapshot_consumers → economics_panel. Placeholder prices shown
until server ships EconomySnapshot (#822).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 13:22:20 +02:00
jpmschweitzerandClaude Opus 4.6 88c7407cb6 style(client): gdformat all 52 GDScript files — zero format warnings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 11:09:10 +02:00
jpmschweitzerandClaude Opus 4.6 44cc8cda4c fix(ui): data rows clip to one line, panel clamped to screen
ImplantDataRow uses clip_text + ellipsis instead of wrapping — each
info item stays on one line. Panel position clamped so bottom edge
never exceeds screen bounds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:57:35 +02:00
jpmschweitzerandClaude Opus 4.6 f0c6e97742 fix(ui): correct Godot 4.6 size flag constants
SIZE_FLAGS_FILL → SIZE_FILL, SIZE_FLAGS_SHRINK_END → SIZE_SHRINK_END.
The _FLAGS_ prefix was removed in Godot 4.6.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:54:11 +02:00
jpmschweitzerandClaude Opus 4.6 6ad1c8255f fix(ui): implant panel width constraint and text wrapping
Panel now clips content and constrains children to its width.
Components set autowrap and SIZE_FLAGS_FILL so text wraps within
the panel instead of overflowing. Bold markdown markers stripped
in ImplantTextBlock constructor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:51:25 +02:00
jpmschweitzerandClaude Opus 4.6 962596fd57 feat(ui): implant component library + star map refactor (D-169)
New component library at client/ui/implant/:
- ImplantTheme: shared Resource with colors, spacing, font sizes
- ImplantPanel: PanelContainer root with themed background/border
- ImplantHeader: title + subtitle
- ImplantSeparator: themed horizontal rule with above/below spacing
- ImplantDataRow: single-line text with optional color override
- ImplantTextBlock: RichTextLabel for wrapping narrative text
- default_implant.tres: default theme resource

Star map info panel refactored from 140 lines of manual draw_string
calls to 50 lines of component composition via _rebuild_info_panel().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:47:23 +02:00