Map Scene Overhaul — 2.5D Adventurer Scene
Map Scene Overhaul — 2.5D Adventurer Scene
Status: Designed Author: game-designer Created: 2026-04-07 System Index: #15 — Solo Map UI (replaces flat node graph) Depends On: map-system.md, game-state-manager.md, player-resources.md
1. Overview
The Map Scene Overhaul replaces the current flat top-down node graph (solo_map_screen.gd
map_visual.gd) with an immersive 2.5D diorama. An adventurer figure stands center-screen holding a map scroll in one hand. The scene is populated with diegetic prop objects that correspond directly to the next available map nodes on the current floor — a cloaked merchant for a shop, a stone altar for a shrine, a campfire for a rest node, and so on. Players interact with the scene in two complementary ways: clicking a prop object directly, or opening the map scroll overlay for the familiar node-graph view. The backpack prop on the adventurer's back opens a build summary panel. The existing map generation logic, node data, and all navigation rules remain unchanged — only the presentation layer is replaced.
2. Player Fantasy
Target MDA Aesthetic: Fantasy + Discovery + Narrative
The player should feel like an adventurer standing at a crossroads, surveying what lies ahead. The scene makes the abstract node graph tangible — instead of clicking a colored icon on a graph, the player sees the silhouette of an armored elite waiting in the shadows, or a merchant's lantern flickering in the mist. The map scroll in-hand reinforces the fiction that the adventurer is actively navigating a dungeon. The backpack prop gives the player a natural, world-grounded reason to review their build. Every interaction feels like a decision made by the character, not a UI menu click.
Self-Determination Theory alignment:
- Autonomy: multiple interaction paths (direct scene click OR map scroll) preserve choice.
- Competence: scene props telegraph encounter difficulty (elite silhouette looks dangerous; campfire looks safe), rewarding players who learn the visual language.
- Relatedness: the adventurer figure and their props create a persistent avatar the player identifies with across runs.
3. Detailed Design
3.1 Scene Layout
The scene is a single Control node rendered over a parallax background,
consistent with the existing 1-bit pixel art style.
┌─────────────────────────────────────────────────────────┐
│ [FLOOR / ACT LABEL] [HP Bar] [Gold Counter] │
│ │
│ │
│ [PROP A] [ADVENTURER] [PROP B] │
│ (center) │
│ [PROP C] [PROP D] │
│ │
│─────────────────────────────────────────────────────────│
│ Inspect bar: hover text / node description │
└─────────────────────────────────────────────────────────┘
- Adventurer figure: always center-screen, slightly below vertical center to leave visual breathing room above.
- Scene props: positioned left and right of the adventurer in a shallow
arc, using fixed anchor positions (up to 4 slots). Positions are defined in
assets/data/map_scene_config.tresas offset Vector2 values relative to screen center. - Inspect bar: identical panel to the existing
hub_screen.gdinspect bar — bottom of screen, hover shows node title + description text. - Floor/Act label: top-left, e.g. "Act 1 — Floor 3".
- HP and Gold: top-right, read from PlayerResources.
3.2 Adventurer Figure
The adventurer is a TextureRect using a dedicated sprite from the Kenney
1-bit pack or a custom composite. The figure has two visible interactive
attachment points:
| Attachment | Sprite | Interaction |
|---|---|---|
| Left hand (map scroll) | Rolled parchment scroll | Click → open Map Scroll overlay |
| Back (backpack) | Travel pack / satchel | Click → open Backpack Panel |
Both attachments use the same AlphaHitRect + outline shader hover system
already established in hub_screen.gd. Hover outline color distinguishes
them: map scroll uses gold tint, backpack uses warm brown tint.
The adventurer figure itself is not interactive — only the two attachment props are clickable. Mouse filter on the base figure texture is IGNORE.
3.3 Scene Props — Node Type Mapping
Scene props are TextureRect nodes placed at the available anchor slots. Each
prop maps to exactly one map node type. When the player clicks a prop, the
system navigates to that node (equivalent to clicking the node on the graph).
| Node Type | Prop Name | Visual Description |
|---|---|---|
combat | Skull Marker | Weathered skull on a stake, basic enemy motif |
elite | Armored Silhouette | Backlit silhouette of a large armored figure |
boss | Boss Silhouette | Towering dark silhouette, distinctive per act |
shop | Hooded Merchant | Cloaked figure with a lantern and pack |
rest | Campfire | Small campfire with ember particle effect |
trap | Trap Glyph | Glowing floor rune or spike trap outline |
shrine | Stone Altar | Flat stone slab with glowing carved symbol |
temple | Temple Pillars | Two stone pillars with elemental glow |
hidden_room | Hidden Door | Partially-ajar stone door in a wall fragment |
event | Notice Board | Wooden signpost with a pinned parchment |
Each prop has:
- A default idle state (static sprite).
- A hover state: outline shader activates, inspect bar shows node title +
description (same text as
NODE_INFOdictionary insolo_map_screen.gd). - A locked state: if the prop corresponds to a node NOT reachable from the player's current position, it is rendered at 40% opacity and is not clickable. This communicates path exclusivity — not every visible prop is accessible on every route.
3.4 Scene Props — Placement Rules
Up to 4 prop slots are available in the scene (left-far, left-near, right-near, right-far). The slot assignment algorithm:
assign_prop_slots(available_nodes: Array[MapNode]) -> Dictionary[int, MapNode]:
# available_nodes: nodes reachable from the current node (1-4 nodes)
# returns: slot_index → MapNode
slots = [LEFT_FAR, LEFT_NEAR, RIGHT_NEAR, RIGHT_FAR]
# Sort nodes by a canonical order: combat < elite < shop < rest < shrine
# < temple < hidden_room < event < trap < boss
# This ensures consistent slot assignment for the same node set.
sorted_nodes = sort_by_node_priority(available_nodes)
result = {}
for i in min(sorted_nodes.size(), slots.size()):
result[slots[i]] = sorted_nodes[i]
return result
If fewer than 4 nodes are available, the unused slots remain empty (no prop rendered). If more than 4 nodes are somehow available (map generation edge case), only the first 4 in canonical order are shown as props; the rest remain accessible only via the map scroll overlay.
3.5 Map Scroll Overlay
The map scroll is the entry point to the existing node graph. Clicking the adventurer's scroll hand triggers:
-
Unroll animation: a parchment TextureRect anchored to the left-hand position tweens its
scale.yfrom 0.0 to 1.0 over 0.25 seconds (Tween.TRANS_BACK,ease_out), then fades in content at alpha 0 → 1 over 0.15 seconds. -
Overlay content: the existing
MapVisualcomponent renders inside the scroll panel. All existing map node click behavior is preserved exactly. The scroll is a modal overlay — it dims the scene behind it at 60% alpha. -
Close: a small "X" button in the scroll's top-right corner, or pressing Escape / UI Cancel input action. Closing plays the reverse animation (reroll).
The scroll overlay does not replace the map — it wraps the existing MapVisual
component unchanged. No modifications to map_visual.gd are required for the
overlay to function.
3.6 Backpack Panel
Clicking the adventurer's backpack opens a panel showing the player's current build state. This panel is distinct from the map scroll and covers the right-side of the screen as a slide-in drawer.
Panel sections (top to bottom):
| Section | Content |
|---|---|
| Archetype header | Archetype name, icon, passive description |
| HP / Gold | Current and max HP, current gold, block if any |
| Relics | Grid of relic icons with hover tooltips (name + effect) |
| Consumables | Row of consumable slots (filled / empty), hover tooltips |
| Stats summary | Dice count, rerolls remaining, manipulations available |
The panel is read-only — no actions can be taken from it. It is a reference view only. Clicking anywhere outside the panel, or pressing Escape / UI Cancel, closes it.
Slide-in animation: the panel enters from the right edge, translating
offset_right from +400 to 0 over 0.2 seconds (Tween.TRANS_QUART,
ease_out). Close is the reverse.
3.7 Interaction Flow
The complete player journey through the Map Scene each floor:
[Arrive at Map Scene]
↓
Scene displays: adventurer + props for next available nodes
↓
Player hover prop → inspect bar shows node type description
↓
Player choice: click prop OR open map scroll
├── [Click prop directly]
│ → confirm_node_selection(node)
│ → SoloGameManager transitions to the selected node's encounter
│
└── [Open map scroll]
→ scroll unroll animation
→ MapVisual renders inside scroll
→ Player clicks node on graph
→ scroll roll-up animation
→ confirm_node_selection(node)
→ SoloGameManager transitions
confirm_node_selection is the single shared path regardless of interaction
method. It calls the same select_node(node_index) function defined in the
Map System GDD.
3.8 Coexistence with the Existing Map
The existing solo_map_screen.gd and map_visual.gd are not deleted. The
new scene wraps them:
solo_map_screen.gdis renamed tomap_scene.gdand extended with the new adventurer/prop logic.map_visual.gdis used unmodified inside the map scroll overlay.- The
NODE_INFOdictionary insolo_map_screen.gdis promoted to a shared resource inassets/data/node_info.tresso both the prop inspect text and the scroll overlay tooltips draw from the same source.
The SceneManager route &"map" continues to point to MapScene.tscn
(renamed from SoloMap.tscn). No other system changes its scene routing.
4. Edge Cases
| Case | Resolution |
|---|---|
| Only 1 available node (linear path) | One prop rendered center-screen. Slots 2-4 empty. Scroll still accessible for full map view. |
| 4+ available nodes | First 4 (canonical sort) shown as props. Remaining nodes accessible only via scroll. A tooltip on the scroll prompts: "More paths available — open map." |
| Boss node available | Boss prop rendered regardless of canonical sort position — boss always takes the rightmost filled slot (RIGHT_FAR or RIGHT_NEAR). |
| Hidden room node | Hidden door prop renders at partial opacity (60%) even when reachable, communicating its mysterious nature. Its inspect bar text reads: "Unknown — contents concealed." |
| Player arrives at a floor with 0 available nodes | This should not occur (map generation guarantees connectivity). If it does, log a warning and fall through to the scroll overlay with an error message: "Path unclear — consult the map." |
| Backpack panel open while map scroll is also open | Not permitted. Opening one closes the other. If the backpack is open and the scroll is clicked, backpack closes first (reverse animation completes), then scroll opens. |
| Props from a previous floor remain visible during transition | Scene props are cleared and rebuilt every time the Map Scene is entered via _ready(). No stale state. |
| Player has no relics or consumables | Backpack panel sections for relics/consumables show "None" placeholder text. Panel still opens normally. |
| Screen resolution smaller than panel width | Backpack panel caps at 90% screen width. Relic grid refluxes to 3 columns (from 4). |
| Prop node is locked (path not reachable) | Prop is visible at 40% opacity, not clickable, hover shows: "[Inaccessible] This path diverged earlier." This gives players spatial context for map branching. |
5. Dependencies
Upstream (what this system reads from)
| System | Dependency Type | Interface |
|---|---|---|
| Map System | Hard | get_available_nodes(current_node_index) — provides node list for prop generation |
| Game State Manager | Hard | confirm_node_selection(node_index) — scene transition trigger |
| Player Resources | Hard | Reads HP, max HP, gold, block for status display |
| Relic System | Soft | Reads active relic list for backpack panel |
| Consumable Database | Soft | Reads held consumables for backpack panel |
| Archetype Data | Soft | Reads current archetype name + passive for backpack panel |
| Audio Manager | Soft | Plays SFX for scroll open/close, prop hover, prop select |
Downstream (what reads from this system)
| System | Dependency Type | Interface |
|---|---|---|
Map Visual (map_visual.gd) | Hard | Embedded inside scroll overlay, unchanged |
| Solo Map Screen | Hard | This system replaces and wraps it |
Contracts
- This system NEVER modifies map state directly. It calls Map System functions.
- This system NEVER modifies player state directly. It calls Game State Manager functions.
- The
NODE_INFOdata source (assets/data/node_info.tres) is owned by this system and provided to Map Visual for tooltip parity. - Prop click and scroll-map click produce identical outcomes — the same
select_nodecall path.
Bidirectional note for Map System GDD
The Map System GDD (map-system.md) lists Solo Map UI as a downstream
dependent. This document extends that relationship: the Map Scene now wraps
the Map Visual component AND provides a diegetic prop layer on top of the
existing map UI. The Map System GDD should be updated to reference this
document under its Dependencies section.
6. Tuning Knobs
All values live in assets/data/map_scene_config.tres. None are hardcoded.
| Knob | Default | Safe Range | Category | Affects |
|---|---|---|---|---|
prop_slot_positions | 4 Vector2 offsets | Any screen-space values | Feel | Prop spacing and visual balance |
locked_prop_opacity | 0.40 | 0.20 – 0.60 | Feel | How visible inaccessible paths are |
hidden_room_prop_opacity | 0.60 | 0.40 – 0.80 | Feel | Mystery level of hidden room prop |
scroll_unroll_duration | 0.25s | 0.15s – 0.50s | Feel | Map scroll open speed |
scroll_reroll_duration | 0.20s | 0.10s – 0.40s | Feel | Map scroll close speed |
backpack_slide_duration | 0.20s | 0.10s – 0.35s | Feel | Backpack panel open/close speed |
dim_overlay_alpha | 0.60 | 0.40 – 0.80 | Feel | Scene dimming when scroll is open |
prop_hover_outline_tween_duration | 0.14s | 0.08s – 0.25s | Feel | Hover feedback speed (matches hub) |
max_props_visible | 4 | 2 – 4 | Gate | How many nodes can be direct-clicked |
node_priority_order | combat, elite, shop, rest, shrine, temple, hidden_room, event, trap, boss | Reorderable | Gate | Which nodes get prop slots first |
7. Visual and Audio Requirements
7.1 Sprite List Required
All sprites use the 1-bit pixel art style (4-tone greyscale, Kenney pack or custom matching the pack's visual language).
| Sprite ID | Description | Source |
|---|---|---|
adventurer_center | Adventurer standing figure, facing camera 3/4 view | Custom / Kenney character |
prop_scroll | Rolled parchment scroll (map scroll, left hand) | Kenney 1-bit |
prop_backpack | Travel satchel / pack on back | Kenney 1-bit |
prop_skull_marker | Skull on a stake (combat) | Kenney 1-bit |
prop_elite_silhouette | Large armored figure silhouette | Custom (solid fill) |
prop_boss_silhouette_act1 | Beholder-esque silhouette | Custom |
prop_boss_silhouette_act2 | Kraken tentacle silhouette | Custom |
prop_boss_silhouette_act3 | Demon silhouette | Custom |
prop_merchant | Hooded figure with lantern | Kenney 1-bit |
prop_campfire | Small campfire (static frame) | Kenney 1-bit |
prop_trap_glyph | Glowing rune circle | Custom |
prop_stone_altar | Flat carved altar | Kenney 1-bit |
prop_temple_pillars | Two stone pillars | Kenney 1-bit |
prop_hidden_door | Slightly open stone door in wall section | Custom |
prop_event_noticeboard | Wooden signpost with parchment | Kenney 1-bit |
scroll_parchment_bg | Open scroll background for overlay | Kenney 1-bit |
Boss silhouettes are per-act variants. The act index from SoloGameManager
determines which boss prop sprite is loaded.
7.2 Animations Required
| Animation | Method | Description |
|---|---|---|
| Scroll unroll | Tween (scale.y 0→1) | Parchment appearing from rolled state |
| Scroll reroll | Tween (scale.y 1→0) | Parchment returning to rolled state |
| Backpack slide open | Tween (offset_right) | Drawer entering from right edge |
| Backpack slide close | Tween (offset_right) | Drawer exiting to right edge |
| Prop hover outline | Tween (shader_parameter/outline_alpha) | Consistent with hub_screen.gd |
| Scene dim overlay | Tween (modulate.a) | Behind-scroll scene dimming |
| Campfire ember | AnimatedSprite2D or shader | Looping ember glow on rest prop |
| Trap glyph pulse | Shader (sin wave on emission) | Slow pulse on trap prop |
| Temple pillar glow | Shader (elemental color pulse) | Slow color pulse |
All animations must be skippable and respect the user's motion preference
setting (per ui-code.md rules). When motion is reduced, all tweens use
Tween.TRANS_LINEAR at 0.05s duration (effectively instant).
7.3 Audio Requirements
All audio events route through AudioManager using existing SFX enum values
or new entries. Required SFX events:
| Event | Trigger | Suggested SFX Category |
|---|---|---|
MAP_SCROLL_OPEN | Scroll unroll begins | Paper / parchment rustle |
MAP_SCROLL_CLOSE | Scroll reroll begins | Paper rustle (shorter) |
BACKPACK_OPEN | Backpack panel slides in | Leather creak / buckle |
BACKPACK_CLOSE | Backpack panel slides out | Leather creak (softer) |
PROP_HOVER | Mouse enters any prop hitbox | Subtle ambient chime |
PROP_SELECT | Prop clicked (node selected) | Weight: boot step or stone scrape |
PROP_LOCKED | Locked prop clicked | Muted thud / no-entry sound |
If SFX assets are unavailable, fall back to existing UI_CLICK and UI_HOVER
events from the existing SFX enum. New entries should be added to
AudioManager.SFX enum when audio assets are sourced.
8. UI Requirements
8.1 Layout Constraints
- Scene must be functional at both minimum (1024×600) and maximum (1920×1080) supported resolutions.
- Prop positions defined as screen-relative anchor offsets, not absolute pixel positions, to support resolution scaling.
- The backpack panel must not overlap the adventurer figure at any resolution. At resolutions narrower than 1280px, the backpack panel uses a full-screen modal rather than a side drawer.
8.2 Keyboard / Gamepad Support
Per ui-code.md, all interactions must support keyboard and gamepad:
| Action | Keyboard | Gamepad |
|---|---|---|
| Cycle through props | Tab / Shift+Tab | D-pad left/right |
| Select focused prop | Enter | A / Cross |
| Open map scroll | M | Y / Triangle |
| Open backpack | B | X / Square |
| Close overlay / panel | Escape | B / Circle |
When a prop has keyboard focus, the outline shader activates (same visual as mouse hover). A small keyboard-focus indicator (pixel-art bracket corners) appears around the focused prop.
8.3 Inspect Bar
Identical implementation to hub_screen.gd's inspect bar:
- Bottom of screen, full width.
- Shows node title (bold, gold) and description text (muted warm tone).
- Default state: "Hover a destination to inspect."
- Inspect bar text comes from
NODE_INFO/node_info.tres.
8.4 HUD Elements
- Floor / Act label: top-left. Format: "Act [N] — Floor [N]".
Reads from
SoloGameManager.current_actandSoloGameManager.current_floor. - HP bar: top-right, same visual as combat screen HP bar for consistency. Shows current / max HP with color gradient (green → yellow → red).
- Gold counter: top-right below HP. Coin icon + number. Both HP and gold update reactively via signals from PlayerResources.
9. Acceptance Criteria
Functional Criteria
| # | Criterion | Verification Method |
|---|---|---|
| 1 | Props rendered match available nodes from map system | Unit test: mock 3 available nodes of known types, assert 3 props with correct sprites appear |
| 2 | Clicking a prop triggers the same node selection as clicking the scroll map | Integration test: click prop, verify select_node called with correct index |
| 3 | Locked props (unreachable paths) are non-clickable and visually distinct | Manual test: navigate past a fork, verify the non-taken path's props render at 40% opacity and do not respond to clicks |
| 4 | Map scroll overlay opens and closes with animation | Manual test: click scroll, observe unroll animation; click X, observe reroll animation |
| 5 | Map scroll embeds existing MapVisual component unchanged | Code review: MapVisual instantiated inside scroll panel with no modifications |
| 6 | Backpack panel shows correct relic, consumable, and archetype data | Manual test: equip 3 known relics, open backpack, verify all 3 visible with correct names |
| 7 | Backpack and scroll cannot both be open simultaneously | Manual test: open backpack, click scroll — backpack closes, scroll opens |
| 8 | Prop slot count never exceeds 4 | Unit test: mock 6 available nodes, assert only 4 props rendered |
| 9 | Boss node prop always occupies the rightmost available slot | Unit test: mock boss + 2 combat nodes, assert boss prop is in RIGHT_FAR slot |
| 10 | Floor and Act labels show correct values | Integration test: advance to floor 5 act 2, open map scene, verify labels read "Act 2 — Floor 5" |
| 11 | HP and gold display updates when values change | Integration test: take damage, verify HP bar updates before next frame |
| 12 | Keyboard navigation cycles through props and activates selection | Manual test: tab through props, press Enter, verify correct node selected |
Experiential Criteria (Playtest Validation)
| # | Target Experience | Validation Question |
|---|---|---|
| E1 | Player understands they can click props AND use the map scroll | After 2 sessions with no tutorial, can players navigate using only props without being prompted? |
| E2 | Prop visual design communicates encounter danger level | Can 5 out of 5 playtesters correctly rank "safest to most dangerous" prop from visual alone? |
| E3 | Backpack panel feels like a natural "check your gear" moment | Do playtesters open the backpack unprompted before engaging an elite or boss prop? |
| E4 | The scene does not feel slower than the previous flat map | Time-to-node-selection from scene entry is ≤ 8 seconds on average in playtesting |
| E5 | Map scroll feels like a safety valve, not the primary method | Ratio of direct prop clicks to scroll-then-click is >= 60:40 after the first 3 runs |