Ryu App UI
Use the Ryu App UI contract for every Companion surface. The app owns its domain data and behavior;
Ryu owns the visual grammar, generic interaction states, and theme.
v1 is the stable contract version, not a rollout label. A Companion is not v1-compliant until
its entrypoint uses RyuAppShell, its CSS imports the shared contract, and its generic chrome is
made from the fixed Ryu roles below.
Required foundation
- Mark the mounted root with
markCompanionAppRoot from @ryu/app-host/companion-theme.
- Import
@ryu/ui/app-ui.css from the app's CSS entrypoint.
- Call
subscribeCompanionTheme() before mounting when the host bridge is available.
- Use
@ryu/ui for controls, dialogs, menus, badges, status, loading, and empty states.
- Use
@ryu/blocks/companion/app-ui for app-level composition primitives.
- A dependency-free static satellite that is mirrored outside the monorepo may use a local
contract-compatible adapter, but it must keep the same v1 root attributes, semantic tokens, and
navigation ownership. It may not introduce a second visual vocabulary.
- Do not render a primary navigation sidebar inside the Companion. Declare the app's sidebar items
in
manifest.json under contributes.sidebar_sections / contributes.sidebar_buttons; Ryu
renders them in the hosted shell and in the standalone Ryu App window.
import { markCompanionAppRoot } from "@ryu/app-host/companion-theme";
import { RyuAppShell, RyuAppToolbar } from "@ryu/blocks/companion/app-ui";
const root = document.getElementById("ryu-plugin-root");
if (root) {
markCompanionAppRoot(root);
root.replaceChildren();
}
export function App() {
return (
<RyuAppShell>
<RyuAppToolbar title="My app" />
{/* domain content */}
</RyuAppShell>
);
}
Fixed vocabulary
Prefer these roles instead of inventing one-off shells:
RyuAppShell - root surface with standard, editor, and canvas modes.
RyuAppToolbar - title and action row.
RyuAppMain and RyuAppSection - page structure and grouping.
RyuAppList, RyuAppListSection, and RyuAppListItem - selectable collection rows.
RyuAppDetail - selected-item or inspector pane.
RyuAppForm and RyuAppField - consistent form structure.
RyuAppEmpty and RyuAppActions - recovery and action treatment.
Every app entrypoint must compose the mounted component through RyuAppShell, even when the app
uses a specialized editor or canvas renderer inside it. This keeps standalone and hosted rendering
on the same visual root.
Use @ryu/ui primitives inside those roles. Do not add a second button, card, input, tab, or
theme implementation in the satellite.
Rules for generated UI
- Do not invent raw colors, radii, shadows, or typography scales.
- Do not use arbitrary gradient or glass treatment to make a surface feel designed.
- Every async surface needs loading, empty, error, offline, and disabled states where applicable.
- Keep domain-specific graph, canvas, media, and editor rendering inside
surface="canvas" or
surface="editor"; keep its controls on Ryu primitives.
- A domain inspector or canvas tool rail is allowed when it edits the current object. It is not a
substitute for app navigation and should not contain the app's top-level sections.
- Check the rendered surface in light and dark themes, narrow widths, keyboard focus, and reduced
motion. A successful typecheck does not prove App UI contract compliance.
Source of truth
The implementation is in packages/ui/src/styles/app-ui.css and
packages/blocks/src/companion/app-ui.tsx. Do not copy the token block into an app. If a pattern
is missing, add it to the shared contract once and migrate all consumers to it.
App identity
When creating or refreshing an app, load ryu-app-icon when available. Author filled, layered artwork and render it with Icon Composer. The host displays completed icons directly. Keep any separately declared Companion glyph consistent and inspect light/dark catalog and detail views.
1---2name: ryu-app-ui3description: Build or migrate a Ryu Companion app with the fixed Ryu App UI v1 vocabulary. Use when an app needs buttons, forms, lists, detail panes, dashboards, empty states, or any visual polish shared with other Ryu apps.4---56# Ryu App UI78Use the Ryu App UI contract for every Companion surface. The app owns its domain data and behavior;9Ryu owns the visual grammar, generic interaction states, and theme.1011`v1` is the stable contract version, not a rollout label. A Companion is not v1-compliant until12its entrypoint uses `RyuAppShell`, its CSS imports the shared contract, and its generic chrome is13made from the fixed Ryu roles below.1415## Required foundation1617- Mark the mounted root with `markCompanionAppRoot` from `@ryu/app-host/companion-theme`.18- Import `@ryu/ui/app-ui.css` from the app's CSS entrypoint.19- Call `subscribeCompanionTheme()` before mounting when the host bridge is available.20- Use `@ryu/ui` for controls, dialogs, menus, badges, status, loading, and empty states.21- Use `@ryu/blocks/companion/app-ui` for app-level composition primitives.22- A dependency-free static satellite that is mirrored outside the monorepo may use a local23 contract-compatible adapter, but it must keep the same v1 root attributes, semantic tokens, and24 navigation ownership. It may not introduce a second visual vocabulary.25- Do not render a primary navigation sidebar inside the Companion. Declare the app's sidebar items26 in `manifest.json` under `contributes.sidebar_sections` / `contributes.sidebar_buttons`; Ryu27 renders them in the hosted shell and in the standalone Ryu App window.2829```tsx30import { markCompanionAppRoot } from "@ryu/app-host/companion-theme";31import { RyuAppShell, RyuAppToolbar } from "@ryu/blocks/companion/app-ui";3233const root = document.getElementById("ryu-plugin-root");34if (root) {35 markCompanionAppRoot(root);36 root.replaceChildren();37}3839export function App() {40 return (41 <RyuAppShell>42 <RyuAppToolbar title="My app" />43 {/* domain content */}44 </RyuAppShell>45 );46}47```4849## Fixed vocabulary5051Prefer these roles instead of inventing one-off shells:5253- `RyuAppShell` - root surface with `standard`, `editor`, and `canvas` modes.54- `RyuAppToolbar` - title and action row.55- `RyuAppMain` and `RyuAppSection` - page structure and grouping.56- `RyuAppList`, `RyuAppListSection`, and `RyuAppListItem` - selectable collection rows.57- `RyuAppDetail` - selected-item or inspector pane.58- `RyuAppForm` and `RyuAppField` - consistent form structure.59- `RyuAppEmpty` and `RyuAppActions` - recovery and action treatment.6061Every app entrypoint must compose the mounted component through `RyuAppShell`, even when the app62uses a specialized editor or canvas renderer inside it. This keeps standalone and hosted rendering63on the same visual root.6465Use `@ryu/ui` primitives inside those roles. Do not add a second button, card, input, tab, or66theme implementation in the satellite.6768## Rules for generated UI6970- Do not invent raw colors, radii, shadows, or typography scales.71- Do not use arbitrary gradient or glass treatment to make a surface feel designed.72- Every async surface needs loading, empty, error, offline, and disabled states where applicable.73- Keep domain-specific graph, canvas, media, and editor rendering inside `surface="canvas"` or74 `surface="editor"`; keep its controls on Ryu primitives.75- A domain inspector or canvas tool rail is allowed when it edits the current object. It is not a76 substitute for app navigation and should not contain the app's top-level sections.77- Check the rendered surface in light and dark themes, narrow widths, keyboard focus, and reduced78 motion. A successful typecheck does not prove App UI contract compliance.7980## Source of truth8182The implementation is in `packages/ui/src/styles/app-ui.css` and83`packages/blocks/src/companion/app-ui.tsx`. Do not copy the token block into an app. If a pattern84is missing, add it to the shared contract once and migrate all consumers to it.8586## App identity8788When creating or refreshing an app, load `ryu-app-icon` when available. Author filled, layered artwork and render it with Icon Composer. The host displays completed icons directly. Keep any separately declared Companion glyph consistent and inspect light/dark catalog and detail views.