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.
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.
apps/uiStorybook app: React widgets (apps/ui/src/widgets/), the floaters generated from XUI (apps/ui/src/generated/), the global theme, and theViewer comparetoolbar decorator.tools/xui2reactthe generator CLI: parses XUI, infers layout, maps tags to widgets, and emits a.tsxcomponent, a.messages.tscatalog, and a.stories.tsxstory per floater. See its README.tools/screenshottercaptures the reference screenshots by driving a built viewer over its LEAP plugin protocol. See its README.
bun install
bun run dev # Storybook at http://localhost:6006
bun run typecheck
bun run check # format, lint (incl. Tailwind class order) and type-checkRegenerate components from XUI (reads ../slv-react unless XUI_VIEWER_ROOT is set):
bun run generate
bun run generate:one -- path/to/floater_x.xml
