Free choices
Most menus are a stack of buttons. Free choices place options at absolute positions — hotspots on the stage, sprite faces, inspect scenes. Same story choices object; different container.layout.
Most stories
- Keep script
>lines for ordinary menus (stack). - For clickable art: write the choice as JSON in
story.jsonwith"mode": "free", itemx/y, often"render_mode": "sprite". - Do not combine
shuffleor stackgapwithfree.
Where this lives
| Idea | Path |
|---|---|
| Group mode | choices.container.layout.mode: "stack" | "free" |
| Host | panel (dialogue slot) or overlay (full screen) |
| Faces | Item / pack style.sprite + state_visual |
| Defaults | game.json → layout.choices |
"choices": {
"show_numbers": false,
"container": {
"layout": { "mode": "free", "host": "overlay", "render_mode": "sprite" }
},
"items": [
{ "text": "Door", "target": "enter", "layout": { "x": 420, "y": 280 } },
{ "text": "Leave", "target": "NEXT", "layout": { "x": 900, "y": 600 } }
]
}
Worked pack: examples/example-05-ui-and-polish/themes/choice_yes_no.json.
Same items, same mode: free and render_mode: sprite. The only difference is host: overlay leaves them floating at their absolute x / y, while panel puts them inside the dialogue plate, which grows to fit.
Stack vs free
stack | free | |
|---|---|---|
| Placement | Vertical list | Absolute x / y |
gap / shuffle | OK | Forbidden |
| Typical look | Theme buttons | Sprites + state_visual |
Hover / pressed looks: Shared shapes → state_visual. Full keys: Choices (story). Ordinary menus: Choices and memory · Choice and input looks.