Skip to content

Writing an extension mywant-gui ​

An extension adds to the GUI without changing it: pages, menu entries, pieces of existing screens, settings, and overlay designs. It is one object handed to registerExtension:

ts
import { registerExtension } from '@/extensions/registry';

registerExtension({
  id: 'my-extension',
  routes: [{ path: '/my-page', element: <MyPage /> }],
  menu: [{ id: 'my-page', label: 'Mine', icon: Star, href: '/my-page', color: '#0891b2' }],
  slots: { settingsSection: MySettings },
  overlayDesigns: [myDesign],
});

Registering twice with the same id does nothing the second time.

What an extension can add ​

FieldWhat
routesPages inside the app frame
bareRoutesPages outside it — no header, no sidebar
menuEntries in the app menu
logTabsTabs of the logs page, after its own
slotsComponents put in named places (below)
overlayDesignsDesigns for every overlay — see Designs
interactAnswers the header's bubble; the first registered wins
pluginEndpointsMore endpoints listing runtime want-card plugins
appHooks / layoutHooksHooks run once at the app root / inside the router
setupRun once when registered — for registries and globals of its own

Slots ​

SlotPropsWhere
appRoot—Mounted once at the app root, inside the router
pillCellsboard, compact, below, onPointerDownCells of the global control pill, before its bell (board: the page has a board)
interactOverlayonSayOver the header, for things waiting on an answer
interactProviderSelectopenBeside the header's bubble
settingsSection—A section of the Settings modal
groupDetailsgroupNameBelow a constellation's details
themeMarksthemeName, colorIn a theme's header, after its count
characterDetailscharacterA character's sheet on the Characters page, after the colour and the shape
characterDisplaydisplay, putA character's Display tab, after Icon Style; put(patch) saves part of the display

Several extensions may fill the same slot; they are drawn in registration order.

Built in, or beside ​

An extension reaches the app one of two ways:

  • Built in — imported by web/src/extensions/installed.ts and compiled with the app. The public app ships with none.
  • Installed beside it — a script and stylesheets in ~/.mywant/gui-extensions/<name>/, loaded at startup before the first render. See Runtime extensions.

Either way registerExtension must run before the first render: routes, the menu and hooks are read as fixed from then on. (Overlay designs are the exception — a design that registers late is picked up.)

The canvas extension mywant-guiex ​

mywant-guiex is an extension of this kind, installed beside the app. It adds the /canvas, /kata and related pages and their menu entries, fills the header's mode lamp, the interact overlay and the Settings section, puts the canvas's choices (canvas design, tile and aura, speeds) into the Characters page through characterDetails and characterDisplay, and answers the header's bubble with the robot. Its extension build (vite.extension.config.ts) produces one IIFE, guiex.js, plus guiex.css. Imports of the app's modules (@/…) are not bundled: they become lookups in window.__mywantModules, so the extension and the app share one React, one router and one copy of every store.