Foundations

Game menus

Every menu the player opens in the city — a shop, a garage, a barber, a stranger’s questions — is built one way. The rules are strict so that a new screen looks like the others on the first try.

Anatomy

A real MenuScreen at 1080p, scaled to this page the way the NUI scales it. Six slots, always in the same place.
$1.200$25.400

Kıyafet

Binco · Vespucci

Toplam$200+ vergi
DöndürENTERSeçESCÇık
1

Tabs · Top left

TabsList variant="menu" with Q / E bumpers. The screen’s sections.

2

Wallet · Top right

PriceTags: cash, then bank. Only on screens that cost money.

3

Title + list · Left column, 480px

The screen’s name, a subtitle with where-am-I, then one MenuList.

4

The world · Centre

Empty. The character, the car, the room — what the menu changes.

5

Checkout · Bottom right, 448px

CheckoutBar, with a MenuChoice for the payment above it if needed.

6

Key hints · Foot, right

KeyHintBar separated, at most four hints a row, two rows at most.

Layout

  1. 1Every in-game menu is a MenuScreen. Nothing is positioned by hand; a menu that needs something else is missing a slot — add the slot to the registry, not an absolute div to the page.
  2. 2The centre of the screen stays empty. The world is the point of the menu.
  3. 3A person or a thing offering a few choices (up to nine) is layout="prompt": numbered rows low on the left, no tabs, no wallet, no checkout.
  4. 4One list per screen. A second level replaces the first, with a back row at its top — never two lists side by side.

Type

  1. 1Menus speak only in font-menu — Barlow Condensed, bold, italic, capitals — at the menu sizes: menu-title 64, menu-heading 40, menu-figure 28, menu-tab 22, menu-item 20, menu-hint 15. No other size.
  2. 2Write the copy in sentence case in the locale file; font-menu sets the capitals. Set lang="tr" so i becomes İ.
  3. 3A row label fits on one line at 480px: twenty-two characters is the budget.
  4. 4All text over the world carries text-hud. The components do it; hand-written text must too.

Colour

  1. 1Blocks are menu-block: the dark at 78%. Never a panel, never glass, never a blur inside a menu.
  2. 2White means chosen or focused. Nothing else on a menu is white-filled.
  3. 3The accent fills two things only: the wallet and the total. Never a row, a tab or a button.
  4. 4Neon colours appear only as data: swatches, meters, a rarity glow. Never as a block’s fill.

Shape and space

  1. 1Menu blocks are cut at rounded-menu (2px). No rounded-lg in a menu; pills only for toggles.
  2. 2Blocks stack gap-menu-gap (6px) apart. Rows are h-menu-row (56px). The screen inset is menu-inset (48px).
  3. 3No borders around blocks. A row’s only line is the rule on its left.

Keyboard first

  1. 1A menu is played, not clicked. It opens with a row already chosen (MenuList autoFocus) and every action in it is a key. The menu takes the keyboard without a cursor — the game’s SetNuiFocus(true, false).
  2. 2The cursor is focus, and there is only one. Hovering a row moves that same cursor; a menu never shows a hover highlight and a selection at once.
  3. 3The pointer appears only where pointing is the task: the map, dragging items between inventories, turning a camera with the mouse, placing or drawing in an editor. Any other screen that shows a cursor is a bug.
  4. 4The keys are fixed: ↑ ↓ walk rows, ← → change a stepper, slider, toggle or choice, ENTER selects, BACKSPACE steps back, Q / E switch tabs from anywhere, TAB jumps to checkout and back, ESC closes the whole menu. A numbered row is pressed by its number. A screen-specific action takes a letter (H: Korna) and says so.
  5. 5Tabs never take focus. The keyboard stays in the list, where the work is.
  6. 6Every action shows its key. If it can be done, there is a hint for it; if there is a hint, it works. Mouse hints use the glyphs (LMB, RMB, WHEEL, MOUSE), never the words.
  7. 7No native inputs: no <select>, no type="range", no checkbox. In the FiveM NUI they take the keyboard from the game.

Motion and transitions

  1. 1Opening, the world goes first: it blurs and dims over 380ms. Then each piece comes in from its own edge — tabs from the top, the list from the left, the aside and checkout from the right, the hints from the bottom — and the rows follow one another 40ms apart. MenuScreen and MenuList do all of it.
  2. 2Closing is quicker than opening: everything leaves together in 180ms (MenuPresence). A game drops its menu at once.
  3. 3Every change of view says which way it went. The next tab or a step in slides in from the right; the previous tab or a step back from the left. Wrap the title and the list in MenuView with the direction MenuTabs hands you, or ±1 for a drill-down. The travel is 6% of the view over 200ms.
  4. 4The cursor is the only thing that moves on a selection: the white fill wipes in from the left in 120ms and the row juts out. The tabs’ white block glides to the new tab.
  5. 5Values roll: a stepper’s value slides out the way it changed and the new one in behind it. A number never just swaps.
  6. 6Every move makes a sound — the cursor ticks, a value clicks, a tab swaps, ENTER confirms, BACKSPACE drops back, the menu opens and closes — through UiSoundsProvider, mounted once at the app root. The components do it; see Sound for the twelve and their rules. A silent move feels broken in a game.
  7. 7Only a chosen swatch or tile pops. Nothing bounces, loops or pulses in a menu. Under reduced motion the views only fade.

Before a menu ships

A pull request that adds or changes a menu answers yes to every line.
  • Built from MenuScreen and the menu components only — no absolute in the page.
  • Every text node is font-menu at a menu size, or comes from a component.
  • Accent appears on the wallet and the total, nowhere else.
  • Opens with a row chosen and works with the mouse unplugged — unless it is a map, a drag-and-drop or an editor.
  • Every key it listens to has a hint; every view change passes a direction; every move plays a sound; no label selects.
  • Checked in the gallery in NUI 1080p and NUI 1440p: nothing clips, nothing stays small.
  • Copy in both tr and en, sentence case, row labels within 22 characters.

The game’s screens, rebuilt

Five screens from the game’s webview, rebuilt from the rules alone. Full screen and keyboard only: ESC closes a menu, E (F1 for the dashboard) opens it again — watch it come and go.

Building one

Start from the clothing demo’s source: a MenuScreen, its slots filled with the menu components, nothing else.
<MenuScreen
  onClose={close}
  tabs={<MenuTabs items={TABS} value={tab} onValueChange={(value, step) => { setDirection(step); setTab(value); }} />}
  wallet={<PriceTag icon={<Wallet />}>$1.200</PriceTag>}
  title={<MenuView viewKey={tab} direction={direction}>Kıyafet</MenuView>}
  checkout={<CheckoutBar total="$200" note="+ vergi" confirmLabel="Satın al" />}
  hints={<KeyHintBar separated><KeyHint voice="menu" keys="ESC" label="Çık" /></KeyHintBar>}
>
  <MenuView viewKey={tab} direction={direction}>
    <MenuList autoFocus>
      <MenuItem icon={<Shirt />} active>Üst giyim</MenuItem>
      <OptionStepper label="Model" value={model} count={148} onChange={setModel} />
    </MenuList>
  </MenuView>
</MenuScreen>