⚠️ Superseded. This document defers to
HUB_FANOUT.mdin its own header. See that document for the current generalized design direction.
MenuBlock: Dynamic Choice Hubs¶
Status: Early concrete consumer of the broader hub-fanout pattern. See HUB_FANOUT.md for the current generalized design direction, including sandbox-oriented hubs and fanout refresh policies.
MenuBlock extends Block to automatically provision choices from compatible blocks.
Use Cases¶
Location menus: “You’re at the mall. Where to?”
Scene selection: “Which chapter would you like to visit?”
Quest boards: “Available quests” (with conditional availability)
Context menus: Actions based on current world state
Patterns¶
Pull Pattern (Dependencies)
Menu declares what it wants via selection_criteria:
lobby = MenuBlock(
label="mall_lobby",
selection_criteria={'has_tags': {'mall_shop'}},
)
# These match and become menu options
clothing = Block(label="clothing", tags={'mall_shop'})
food = Block(label="food", tags={'mall_shop'})
Push Pattern (Affordances) Blocks offer themselves to compatible menus:
parking = Block(label="parking")
parking.offer_as_affordance(
target_criteria={'has_tags': {'mall_lobby'}}
)
# Parking appears even though menu didn't ask for it
Bidirectional (Both) Pull and push work together - menu gets both shops it asked for AND parking that volunteered.
Scope Control¶
# Only find blocks in same scene
menu = MenuBlock(
selection_criteria={...},
within_scene=True, # Default
)
# Search entire graph
menu = MenuBlock(
selection_criteria={...},
within_scene=False,
)
Action Labels¶
MenuBlock checks block metadata in order:
locals['action_text']- Explicit menu textlocals['menu_text']- Alternative menu textblock.label- Fallback to block’s label
shop = Block(
label="clothing_store_id",
locals={'action_text': "Shop for clothes"}, # This appears in menu
)
Scene Navigation¶
When MenuBlock links to a Scene, it automatically creates Actions to scene.source (the canonical entry point), not to the Scene node itself.
Implementation Notes¶
Creates dependencies during PLANNING phase
Materializes Actions during UPDATE phase
Clears stale dynamic actions before reprovisioning
Supports both pull (dependency) and push (affordance) patterns
Inherits all Block rendering/journaling behavior