Skip to content
Work in progress. These docs describe Spawnite at launch, and some parts are still being built.

UI

The engine’s UI primitives are the only way to draw text, panels, buttons, bars, pictures and controls, each with the house look built in. A raw HTML element inside a game is a lint finding. A game overrides through a variant the engine defines or a className that shows in the diff, and passes a colour, a size or a place that comes from data, such as an item’s rarity colour, as a style on Text, Button, Panel, Image or Slider.

The set: Hud, Panel, Modal, Window; Text, Heading, Bar, Counter, Icon, Image; Button, Joystick, Tap, ActionBar; Draggable and DropTarget; Slider, NumberField, TextField, Select and Toggle; FloatingText, Billboard. The menus, the loading screen, a Bar, an accent or pane Button and the other coloured parts draw from the theme tokens, which a game sets once in its stylesheet or takes from a shipped theme; a primitive’s parts take a class each.

Each one has a story in the Storybook.

A few kinds of UI have no primitive, and a game draws them as raw elements behind an eslint-disable-next-line no-restricted-syntax that says why:

  • A cell that double-clicks or shows a tooltip on hover, which Button’s press does not cover.
  • A tooltip placed by its measured height.
  • A bar, a cell or a shade written through a ref each frame rather than rendered; Bar takes a value.
  • A stick that floats where the finger lands; Joystick stands in a slot.
  • A canvas the game draws on each frame, such as a minimap.
  • A colour picker.
  • An empty decorative box, where Text needs words.

UI sits at any level and the engine hoists it to the screen. The level decides what it reads and how long it lives; see the table. This page is the one that cuts across levels, because Panel appears at every one.

A Panel names a slot and an order, never a position. Slots are the four corners, four edges and centre; each stacks its children, so overlap is impossible. A Hud carries a slot Panel to the screen from any level. A Panel with anchor follows its entity in the world.

A Window is a bag, a character sheet or a shop: several open at once over the game, which keeps playing. It opens in a slot, and the player moves it by its title bar.

A Modal draws over the whole screen, from any level. The engine keeps one modal stack and the top one draws, so two chests open at once show one, then the other. A modal pauses the world only when it passes pause.

The engine re-exports nothing from three. A game that needs it imports from @spawnite/engine/three, so the MCP and a lint rule see every place a game went under the engine.

A game imports the primitives from @spawnite/engine. An app outside a game, or a design system that wraps the primitives in its own look, imports from @spawnite/ui:

  • @spawnite/ui exports the components and the motion, with palette, gripPointer, PointerGripOptions and trackPageHide. Import @spawnite/ui/styles.css once in the application.
  • @spawnite/ui/controls exports Slider, NumberField, TextField, Select and Toggle without the stylesheet, for a design system that wraps them in its own look.
  • @spawnite/ui/motion exports the shared timing without the stylesheet: springs, tap and press, and settleEase, a quick start that settles, for a tween’s transition.ease.
  • @spawnite/ui/tooltip exports Tooltip without the stylesheet.
  • @spawnite/ui/brand exports the brand marks without the stylesheet.

Tooltip is the behaviour of a tooltip with no look of its own: a short delay, then at once for the next control along a row, a portal, placement inside the screen’s edges, reduced motion, and a press that toggles it on a phone. A design system wraps it and passes its look as className, as the devtools do.

A component declares what the debugger shows for its entity with useDevtoolsPanel: readouts, fields and buttons, which the devtools draw in the inspector and over a pinned entity in the world.

The samples on Game, Scene, World and Entity show a Panel at each level and a Modal inside an entity.