Skip to content

Repository files navigation

@gwigz/xui2react

Storybook side-by-side compare: the React render of the Item Properties floater on the left next to the captured viewer screenshot on the right

Converts Second Life viewer XUI (XML UI) into React + Tailwind components, previewed in Storybook and diffed against real viewer screenshots.

XUI positions every widget with absolute pixel coordinates. The generator reconstructs a flex and grid layout from those coordinates, emits React widgets styled with Tailwind, and registers i18n message catalogs from the localized XUI. Each generated component is checked for visual fidelity in Storybook, where a "Viewer compare" overlay diffs the live render against a captured screenshot of the real viewer (side by side, onion-skin, or pixel diff).

XUI, colors, and textures are read from a viewer checkout. By default that is the sibling ../slv-react tree; override with XUI_VIEWER_ROOT.

Example

The generated React render of the test floater in Storybook, element outlines showing its six equal grid columns

Absolute coordinates become inferred layout, repeated structure collapses, and text content is lifted into message catalogs. Here six equally sized, absolutely positioned columns become one CSS grid (the multi-line text content is shown as ):

XUI input (floater_aaa.xml):

<floater name="Test Floater" title="TEST FLOATER" width="650" height="300" can_resize="true">
  <text        left="0"     follows="left|top|bottom" top="5" bottom="-5" width="100" valign="top">…</text>
  <text        left_pad="5" follows="left|top|bottom" top="5" bottom="-5" width="100" valign="center">…</text>
  <text        left_pad="5" follows="left|top|bottom" top="5" bottom="-5" width="100" valign="bottom">…</text>
  <text_editor left_pad="5" follows="left|top|bottom" top="5" bottom="-5" width="100" valign="top">…</text_editor>
  <text_editor left_pad="5" follows="left|top|bottom" top="5" bottom="-5" width="100" valign="center">…</text_editor>
  <text_editor left_pad="5" follows="left|top|bottom" top="5" bottom="-5" width="100" valign="bottom">…</text_editor>
</floater>

Generated React:

<Floater name="test-floater" title={t("title")} width={650} height={325} canClose canResize>
  <div className="grid flex-1 grid-cols-6 gap-1.25 w-156.25 mb-1.25 mt-1.25">
    <Text>{t("text")}</Text>
    <Text valign="center">{t("text-2")}</Text>
    <Text valign="bottom">{t("text-3")}</Text>
    <TextEditor>{t("text-editor")}</TextEditor>
    <TextEditor valign="center">{t("text-editor-2")}</TextEditor>
    <TextEditor valign="bottom">{t("text-editor-3")}</TextEditor>
  </div>
</Floater>

Browse the rest in apps/ui/src/generated, and the reference captures they are diffed against in apps/ui/screenshots/viewer.

Layout

  • apps/ui Storybook app: React widgets (apps/ui/src/widgets/), the floaters generated from XUI (apps/ui/src/generated/), the global theme, and the Viewer compare toolbar decorator.
  • tools/xui2react the generator CLI: parses XUI, infers layout, maps tags to widgets, and emits a .tsx component, a .messages.ts catalog, and a .stories.tsx story per floater. See its README.
  • tools/screenshotter captures the reference screenshots by driving a built viewer over its LEAP plugin protocol. See its README.

Develop

bun install
bun run dev          # Storybook at http://localhost:6006
bun run typecheck
bun run check        # format, lint (incl. Tailwind class order) and type-check

Regenerate components from XUI (reads ../slv-react unless XUI_VIEWER_ROOT is set):

bun run generate
bun run generate:one -- path/to/floater_x.xml

About

Convert XUI to React layouts with absolute to flexbox & grid translations

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages