5 Minute Innovation: The Instrument Case Inventory¶
Proposal: Replace the traditional flat inventory UI with a diegetic 3D instrument case the player swings off their back. Items live inside the case as physical objects in the game world, not in a menu.
The Concept¶
The player carries an instrument case on their back. A quick flick of the right stick swings it around to the front. The lid pops open, revealing compartments of crafting components, tools, 4" vinyl cantrip records, and consumables. Over time, players personalize the case exterior with collectible stickers -- a visible record of achievements and identity.
Why it matters: Everything in The Smithy is about the physical world of music-making. A traditional inventory screen breaks immersion. The case keeps the player inside the world.
System Architecture¶
graph TB
subgraph Evennia["EVENNIA SERVER (Python)"]
IH[InventoryHandler]
DB[(player.db.inventory<br/>player.db.stickers)]
IH --> DB
end
subgraph WS["WEBSOCKET BRIDGE"]
direction LR
S2C["Server → Client<br/>full_sync | slot_update<br/>slot_clear | sticker_added"]
C2S["Client → Server<br/>inventory_move<br/>inventory_use | sticker_place"]
end
subgraph UE5["UE5 CLIENT (C++)"]
WSS[SmithyWebSocketSubsystem]
IDM[InventoryDataManager]
ICC[InventoryCaseComponent]
WBP[WBP_InventoryCase<br/>12-slot grid widget]
WSS --> IDM
IDM --> ICC
ICC --> WBP
end
Evennia <-->|JSON over WebSocket| WS
WS <-->|JSON over WebSocket| UE5
style Evennia fill:#2d4a2d,stroke:#5a5,color:#fff
style UE5 fill:#2d2d4a,stroke:#55a,color:#fff
style WS fill:#4a3d2d,stroke:#a85,color:#fff
Data Flow: Adding an Item¶
sequenceDiagram
participant E as Evennia Server
participant WS as WebSocket
participant DM as InventoryDataManager
participant CC as CaseComponent
participant UI as Slot Widget
E->>WS: inventory_slot_update (JSON)
WS->>DM: ProcessSlotUpdate()
DM->>DM: Update Slots[index]
DM->>CC: OnInventoryChanged broadcast
CC->>UI: Refresh slot grid
UI->>UI: Show icon + stack count
Note over E,UI: ~1 frame latency from server push to visual update
Case Interaction State Machine¶
stateDiagram-v2
[*] --> Closed
Closed --> Opening: Right stick flick / button press
Opening --> Open: Lerp complete (0.4s)
Open --> Closing: Right stick flick / button press
Closing --> Closed: Lerp complete (0.3s)
Open --> Open: Click slot → use item
Open --> Open: Drag slot → reorder
note right of Opening: Case swings from back to front<br/>Lid rotates open (-110 deg)
note right of Closing: Reverse animation<br/>Case returns to back
The Case Interior -- Golden Ratio Layout¶
The case interior follows a golden ratio spiral subdivision, giving each item type a compartment proportional to its importance. The largest section is a vinyl sleeve rack holding 4" cantrip records, spiraling inward through tools and components to the smallest consumable pockets -- mirroring how a DJ's flight case organizes by frequency of use.
Golden Ratio Spiral Subdivision
================================
+---------------------------------+-----------------------+
| | |
| CANTRIP VINYL SLEEVES (3) | TOOLS (3) |
| | +---------+ |
| +------+ +------+ +------+ | | Pliers | |
| | .--. | | .--. | | .--. | | | File | |
| ||4" || ||4" || ||4" || | | Clamp | |
| || () || || () || || () || | +---------+ |
| || || || || || || +----------+----+-------+
| | `--' | | `--' | | `--' | | | | |
| |Melody| |Rhythm| |Harm. | | COMPNTS | | CONS. |
| |Weave | |Pulse | |Bind | | (3) | | (3) |
| +------+ +------+ +------+ | Fork | | Rosin |
| | Wire | | Wax |
| 5 : 8 ratio | Peg | | Dust |
| (padded record dividers) | | | |
+---------------------------------+----------+----+-------+
phi^2 phi^0 phi phi^-1
^-- smallest
compartments
spiral inward
graph LR
subgraph CASE["INSTRUMENT CASE INTERIOR -- Golden Spiral"]
direction LR
subgraph PHI2["CANTRIP VINYLS -- 4in Record Sleeves<br/>(largest: 5 units)"]
direction TB
S6["Melody Weave<br/>4in vinyl"]
S7["Rhythm Pulse<br/>4in vinyl"]
S8["Harmonic Bind<br/>4in vinyl"]
end
subgraph REMAIN[" "]
direction TB
subgraph PHI1["TOOLS<br/>(3 units)"]
direction LR
S3["Pliers"]
S4["File"]
S5["Clamp"]
end
subgraph INNER[" "]
direction LR
subgraph PHI0["COMPONENTS<br/>(2 units)"]
direction TB
S0["Tuning Fork"]
S1["Wire Spool"]
S2["Bridge Peg"]
end
subgraph PHIM1["CONSUMABLES<br/>(1 unit)"]
direction TB
S9["Rosin Cake"]
S10["Seal Wax"]
S11["Fae Dust"]
end
end
end
end
style PHI2 fill:#2d2d4a,stroke:#77a,color:#fff
style PHI1 fill:#2d4a3d,stroke:#5a7,color:#fff
style PHI0 fill:#4a3d2d,stroke:#a85,color:#fff
style PHIM1 fill:#4a2d3d,stroke:#a57,color:#fff
Golden ratio proportions (Fibonacci): Compartment areas follow 5 : 3 : 2 : 1 -- each section roughly phi (1.618) times the next smaller one, spiraling inward from the record sleeves to the consumable nooks.
| Compartment | Slots | Ratio | Design Intent |
|---|---|---|---|
| Cantrips (4" vinyl sleeves) | 3 | 5 | Largest -- learned musical spells stored as miniature records in padded dividers |
| Tools | 3 | 3 | Mid-size -- reusable workshop equipment, held in elastic loops |
| Components | 3 | 2 | Smaller -- crafting materials in lined compartments |
| Consumables | 3 | 1 | Smallest -- single-use items tucked in corner pockets |
Greybox Milestones¶
gantt
title Greybox Prototype Milestones
dateFormat X
axisFormat %s
section Backend
M1 Data Layer (Evennia) :m1, 0, 1
M2 WebSocket Bridge :m2, after m1, 1
section Frontend
M3 Static Case + Slots :m3, after m2, 1
M4 Click Interaction :m4, after m3, 1
M5 Open/Close Animation :m5, after m4, 1
M6 Gesture Input (Stick Flick) :m6, after m5, 1
M7 Sticker System :m7, after m5, 1
| Milestone | Acceptance Criteria |
|---|---|
| M1 Data Layer | Manipulate inventory via Evennia commands, data persists |
| M2 WebSocket Bridge | UE5 connects, receives full sync, logs parsed data |
| M3 Static Case | Inventory UI visible in world, shows synced data |
| M4 Interaction | Point at slots, click them, server receives requests |
| M5 Animation | Button press swings case to front and opens lid |
| M6 Gesture Input | Right stick flick toggles case open/close |
| M7 Stickers | Add sticker via Evennia, decal appears on case in UE5 |
Sticker System¶
Players accumulate stickers over time -- achievement markers, band logos, fae symbols. Stickers are DecalComponents positioned on the case mesh surface, synced through the same WebSocket channel.
graph LR
A[Player earns sticker<br/>via Evennia event] --> B[StickerData stored<br/>in player.db]
B --> C[sticker_added pushed<br/>via WebSocket]
C --> D[CaseComponent spawns<br/>DecalComponent]
D --> E[Decal positioned on<br/>case exterior mesh]
style A fill:#4a3d2d,stroke:#a85,color:#fff
style E fill:#2d2d4a,stroke:#55a,color:#fff
Each sticker carries: position (x,y normalized 0-1), rotation, scale, and an asset reference. The case becomes a personal artifact that tells the player's story.
Tech Stack Summary¶
| Layer | Technology | Role |
|---|---|---|
| Backend | Evennia (Python 3.11) | Inventory state, persistence, game logic |
| Protocol | WebSocket + JSON | 7 message types (4 server-push, 3 client-request) |
| Frontend | UE5.6 C++ | Case mesh, widget, animation, input |
| Input | Enhanced Input System | Right stick gesture detection + button fallback |
| UI | UMG + Common UI | Gamepad-navigable slot grid on WidgetComponent |
Discussion Points¶
- Slot count: Is 12 right, or do we need room to grow?
- Gesture input: Right stick flick vs. dedicated button -- should the flick be the primary or secondary method?
- Sticker placement: Should players choose where stickers go, or auto-place?
- Item drag-and-drop: Include in greybox or defer?
- Case art priority: When do we replace greybox geometry with the real instrument case model?